1. 从“搜不到”到“答得准”:得物知识问答的挑战与Agent的破局
在电商和内容社区领域,知识问答系统早已不是新鲜事物。用户想了解一款球鞋的科技、一件潮玩的背景,或者一个穿搭技巧,第一反应往往是去平台的问答板块搜索。然而,一个普遍存在的痛点始终困扰着用户体验:“搜不到”和“答不准”。
“搜不到”意味着传统的基于关键词匹配的搜索引擎,在面对用户口语化、多意图、甚至包含错别字的复杂查询时,显得力不从心。比如用户问“椰子鞋冬天穿会不会冻脚?”,系统可能只会机械地匹配“椰子鞋”和“冬天”,而无法理解用户真正关心的是鞋款的保暖性、材质透气性以及季节性穿搭建议。“答不准”则更致命,系统可能从海量文档中抓取了一段相关但过时、片面甚至矛盾的信息,拼凑成一个看似正确实则误导的答案。在得物这样以“潮流”和“正品”为生命线的社区,一个关于商品材质、鉴定要点或潮流趋势的错误答案,其负面影响是巨大的。
这就是我们团队面临的核心挑战:如何构建一个不仅能“检索”信息,更能“理解”问题、“推理”答案、“组织”表述的智能问答系统?答案就是引入“复合检索 Agent”的设计理念。这不仅仅是把检索技术(Retrieval)和大型语言模型(LLM)简单拼接,而是设计一个具备自主规划、工具调用、多轮交互和反思能力的智能体(Agent)。它像一个拥有专业知识的潮流顾问,接到用户问题后,会主动思考:“这个问题涉及哪几个方面?我需要查询哪些数据源?如何验证信息的时效性和准确性?最终的回答应该如何组织才能清晰且有说服力?”
本次实践,我们基于AgentScope框架,深入探索了如何将ReAct(Reasoning and Acting)范式应用于得物的知识问答场景,构建了一个能够进行复杂决策和精准执行的复合检索 Agent 系统。接下来,我将从系统设计的顶层思考开始,逐步拆解其中的核心架构、关键组件以及我们趟过的那些“坑”。
2. 系统架构全景:当ReAct范式遇见多源异构数据
在设计之初,我们摒弃了“一个模型吃天下”或“检索+生成流水线”的简单思路。我们需要的系统,必须具备动态决策能力。用户的一个问题,背后可能对应着商品详情、用户评测、鉴定百科、社区帖子、品牌官方资讯等多种数据源。系统必须能自主判断该调用哪些工具,按什么顺序调用,以及如何处理可能冲突的结果。
2.1 核心架构设计:基于AgentScope的智能体编排
我们选择AgentScope作为智能体编排框架,而非从零构建。原因在于,AgentScope 提供了开箱即用的多智能体对话管理、丰富的工具集成接口以及灵活的工作流定义能力,让我们能更专注于业务逻辑而非底层通信。我们的系统核心架构如下图所示(概念示意):
用户请求 | v [ 网关 & 请求解析层 ] | (解析问题,初始化会话) v [ 智能体调度中心 (Agent Orchestrator) ] | |-----------------------| | | v v [ 规划与推理智能体 ] [ 工具执行智能体集群 ] | (ReAct 循环核心) | (检索、计算、查询等) | | |-----------------------| | v [ 答案合成与校验智能体 ] | v [ 响应格式化与输出层 ] | v 用户答案架构核心解读:
- 智能体调度中心:这是系统的大脑。它接收解析后的问题,并决定启动哪个或哪几个智能体来协同工作。对于复杂问题,它通常会先启动“规划与推理智能体”。
- 规划与推理智能体 (Planner & Reasoner):这是 ReAct 范式的承载者。它的内部是一个循环过程:
- Reason(思考):分析当前问题,决定下一步需要做什么。例如:“用户问‘AJ1黑红脚趾和芝加哥配色哪个更值得入手?’。这需要比较两款鞋。我需要先分别获取它们的商品详情、当前市场价格趋势和社区口碑。”
- Act(行动):根据思考结果,调用相应的工具。例如:调用
商品详情检索工具获取 AJ1 黑红脚趾的配置、材质、发售信息;调用市场价格查询工具获取近期价格曲线;调用社区情感分析工具扫描相关帖子的正面/负面评价。 - 观察结果,继续循环:获取工具返回的结果后,智能体再次进入“思考”阶段,评估信息是否足够、是否需要补充查询、或发现信息矛盾需要进一步核实。这个过程会持续进行,直到智能体认为已经收集到足够的信息来回答问题,或者达到预设的最大循环次数。
- 工具执行智能体集群:这是一组“手”和“脚”,每个智能体专精于一项具体任务。我们将其微服务化,包括:
- 向量检索工具:负责从商品描述、鉴定点、潮流文章等文本库中,根据问题的语义进行相似性搜索。我们采用混合检索策略,结合了稠密向量检索(如BGE模型)和稀疏检索(如BM25),以平衡召回率和精度。
- 结构化数据查询工具:直接连接数据库,查询商品SKU、价格、库存、品牌信息等精准字段。
- 实时信息获取工具:通过内部API获取实时价格、活动信息、库存状态等。
- 计算与推理工具:进行简单的数值比较、趋势计算、或调用规则引擎进行逻辑判断(如“是否符合免检条件”)。
- 答案合成与校验智能体:当规划智能体收集齐所有信息片段后,会将它们和原始问题一起交给这个智能体。它的职责是:整合、去重、校验矛盾、组织语言。例如,它可能发现商品详情说“材质:头层牛皮”,而某个用户评测说“皮质很硬,疑似人造革”。此时,校验智能体会尝试赋予信息权重(官方详情 > 普通用户评测),或触发新一轮查询(查找更权威的鉴定报告),最终生成一个连贯、准确、注明关键信息来源的答案草稿。
为什么选择 AgentScope 和 ReAct?早期我们尝试过简单的“检索-生成”管道,但发现 LLM 在生成时容易“胡编乱造”检索结果中不存在的信息(幻觉问题)。ReAct 范式强制 LLM 将“思考过程”和“行动依据”外显化,每一步行动都有对应的工具调用和结果观察,极大地增强了过程的可靠性和可解释性。AgentScope 则完美地将这一范式工程化,其多智能体原语让我们能轻松构建上述分工协作的体系。
2.2 数据层设计:混合检索的基石
强大的 Agent 离不开高质量、多模态的数据供给。我们的数据层可以概括为“多源异构、统一索引、分层召回”。
- 多源异构数据:
- 结构化数据:商品数据库(SPU/SKU、属性、价格)、用户订单、鉴定记录。
- 非结构化文本:商品详情页文案、用户评价、社区帖子、潮流百科文章、品牌新闻。
- 半结构化数据:商品标签(如“联名”、“限量”)、用户行为日志(搜索、点击、收藏)。
- 统一向量化索引:我们将所有非/半结构化文本通过同一个嵌入模型(如
BGE-large-zh)转换为向量,存入向量数据库(如 Milvus 或 Qdrant)。这一步的关键在于构建高质量的向量。我们不是简单地将整段文本扔进去,而是进行了“分块”和“元数据增强”:- 智能分块:对于长文档(如一篇球鞋文化文章),按语义段落进行分割,避免检索时丢失细节。
- 元数据注入:为每个文本块附加来源(如“得物鉴定百科”)、实体(如“Air Jordan 1”)、时间戳等信息。这些元数据将在后续检索和答案生成中起到关键过滤和权重作用。
- 分层召回策略:当工具智能体执行检索时,并非简单执行一次向量搜索。其内部流程是:
- 关键词召回:首先使用经过 query 重写后的关键词进行快速召回,保证基础相关性。
- 语义召回:利用向量检索,召回语义上相近的片段,解决表述差异问题。
- 混合排序与重排:将前两步的结果合并,使用更复杂的排序模型(如 Cross-Encoder)进行精排,同时利用元数据(如来源权威性、时效性)进行加权和过滤。
这样的数据层设计,确保了我们的 Agent 在执行“Act”时,能够获取到尽可能全面、准确、相关的信息原料。
3. 核心组件深度拆解:规划、工具与校验
理解了宏观架构,我们深入到三个最核心的组件内部,看看它们是如何具体工作的。
3.1 规划与推理智能体:ReAct循环的实战实现
这是整个系统的“指挥官”。我们将其设计为一个基于 LLM 的循环控制器。以下是一个简化的内部工作流程代码逻辑示意:
# 伪代码,基于 AgentScope 思想 class ReActPlannerAgent: def __init__(self, llm, tools): self.llm = llm # 例如 GPT-4, DeepSeek 或本地化模型 self.tools = tools # 可用的工具集 self.max_steps = 10 self.memory = [] # 存储思考、行动、观察的历史 def run(self, query): self.memory.append(f"问题: {query}") for step in range(self.max_steps): # 1. Reason: 根据历史,思考下一步 prompt = self._build_reason_prompt(query, self.memory) thought = self.llm.generate(prompt) self.memory.append(f"思考: {thought}") # 判断是否应该结束(生成最终答案) if "最终答案" in thought or step == self.max_steps - 1: final_answer = self._synthesize_answer(query, self.memory) return final_answer # 2. Act: 解析思考,调用工具 action, action_input = self._parse_action(thought) if action not in self.tools: self.memory.append(f"观察: 错误 - 未知工具 {action}") continue # 调用工具执行智能体 tool_result = self.tools[action].execute(action_input) self.memory.append(f"行动: 使用 {action} 输入 {action_input}") self.memory.append(f"观察: {tool_result}") def _build_reason_prompt(self, query, memory): # 构建一个引导模型进行结构化思考的提示词 tools_desc = "\n".join([f"- {name}: {func.desc}" for name, func in self.tools.items()]) history = "\n".join(memory[-5:]) # 最近几步历史 return f""" 你是一个专业潮流知识问答助手。请根据用户问题和历史记录,决定下一步行动。 可用工具: {tools_desc} 历史记录: {history} 请严格按以下格式输出: 思考:<你的分析,判断当前需要做什么,为什么> 行动:<工具名称> 或 最终答案 输入:<传递给工具的精确参数,如果是最终答案则写“无”> """关键设计点与踩坑:
- 提示词工程是灵魂:
_build_reason_prompt中的指令必须清晰、结构化,强制 LLM 按格式输出,便于后续解析。我们经历了无数次“模型不听话”的调试,才稳定下来。 - 工具描述要精准:每个工具的描述必须清晰说明其功能、输入格式和输出示例。模糊的描述会导致规划智能体错误调用工具。
- 历史长度控制:将全部历史记录放入提示词会消耗大量 Token 且可能干扰当前决策。我们通常只保留最近3-5轮(思考-行动-观察)记录,并在必要时进行摘要。
- 解析器的鲁棒性:
_parse_action函数必须能处理模型输出的微小变异(如多余的空格、换行、中文标点)。我们采用了正则表达式结合简单自然语言处理的方法,并准备了降级策略。
3.2 工具智能体设计:专精与协同
工具智能体的目标是“专业的事交给专业的模块”。我们为每个工具都设计了独立的智能体,它们封装了具体的业务逻辑和数据访问细节。
以“商品详情向量检索工具”为例,它的内部逻辑远比一个简单的向量搜索复杂:
- 查询理解与重写:接收到的
action_input可能是一个自然语言问题片段。工具智能体首先会调用一个轻量级 Query 理解模型,对其进行纠错、扩展和标准化。例如,将“AJ1黑红”重写为“Air Jordan 1 Black Toe”。 - 混合检索执行:使用重写后的查询,并行执行:
- 关键词检索:在 Elasticsearch 中检索商品标题、核心属性。
- 向量检索:在向量数据库中检索商品描述、评测详情。
- 结果融合与过滤:合并两组结果,根据业务规则过滤掉已下架、无库存或低置信度的商品。
- 格式化输出:将结果组织成规划智能体易于理解的结构化格式,通常包括商品ID、名称、核心属性摘要、相关文本片段以及置信度分数。
// 工具输出示例 { "status": "success", "data": [ { "product_id": "123456", "name": "Air Jordan 1 Retro High OG 'Black Toe'", "snippet": "经典黑红白配色,元年复刻版本,采用优质皮革鞋面...", "relevance_score": 0.92, "source": "product_description" }, // ... 更多结果 ] }工具设计心得:
- 接口标准化:所有工具智能体遵循统一的输入/输出格式,便于调度中心管理。输出必须包含
status(成功/失败)和结构化的data。 - 超时与熔断:每个工具都必须设置合理的超时时间,并接入熔断器。一个缓慢或失败的工具不应拖垮整个 Agent 流程。
- 可观测性:每个工具调用都需要记录详细的日志和指标(如耗时、召回数量、缓存命中率),这是后期性能分析和问题排查的生命线。
3.3 答案合成与校验:对抗“幻觉”的最后防线
这是保证答案质量的守门员。规划智能体收集来的信息可能是碎片化、冗余甚至矛盾的。答案合成智能体的任务就是“去伪存真,化零为整”。
它的工作流程包含几个关键步骤:
- 信息聚合与去重:合并来自不同工具的相同实体的信息。
- 矛盾检测与消解:
- 规则消解:对于明确的规则(如“官方详情优先于普通帖子”),直接应用。
- 基于LLM的消解:对于复杂的矛盾,将矛盾片段和问题提交给 LLM,要求其判断哪个更可信,并给出理由。例如:“片段A(来自2022年文章)说此鞋款使用‘X材料’,片段B(来自2024年品牌公告)说已升级为‘Y材料’。请问当前准确信息是什么?” LLM 可以根据时效性做出判断。
- 结构化信息组织:按照“结论先行、分点论述、注明来源”的原则组织答案。例如,在回答比较类问题时,采用对比表格的形式。
- 安全与合规校验:最后,生成的答案草稿会经过一个安全过滤层,确保不包含违规、歧视性或未经证实的信息。
一个真实的“坑”:我们曾遇到一个案例,用户问“某某联名款是否值得收藏”。检索工具返回了该商品极高的当前市价和一堆“必入”、“神作”的社区评价。如果直接合成,答案会极度乐观。但校验智能体通过调用“历史价格走势工具”发现,该商品价格在发售后已飙升数倍且近期有波动。最终,合成后的答案变成了:“该联名款市场热度极高,当前市价约为发售价的X倍(数据来源:得物行情),社区讨论积极。但需注意,其价格已处于历史高位,近期有Y%的波动(数据来源:价格曲线)。收藏需考虑个人承受能力和对价格波动的预期。” 这种平衡、客观的答案,才是用户真正需要的。
4. 工程化落地:性能、评估与迭代
设计出原型只是第一步,让系统稳定、高效、可评估地运行在得物这样高并发的生产环境,是更大的挑战。
4.1 性能优化与成本控制
Agent 系统的链式调用特性,使其延迟和成本天然高于简单服务。我们的优化策略是多管齐下:
- 异步化与并行:在规划智能体确定可以并行执行的任务时(如同时查询商品A和商品B的详情),通过 AgentScope 的能力发起并行工具调用,大幅减少总等待时间。
- 分层缓存策略:
- LLM 思考缓存:对相同的“问题+历史”指纹,缓存其“思考”和“行动”输出,避免重复计算。
- 工具结果缓存:对工具调用结果进行 TTL 缓存,特别是那些相对静态的数据(如商品基础属性)。
- 最终答案缓存:对完全相同的用户查询,缓存最终生成的答案。
- 模型选型与蒸馏:在推理(Reason)环节,我们尝试使用能力足够强但成本更低的模型(如 DeepSeek、Qwen 系列)。对于答案合成环节,在确保质量的前提下,我们也逐步从 GPT-4 向性能优秀的开源模型迁移。同时,我们探索将复杂的多步 ReAct 过程,通过蒸馏技术,压缩成一个更高效的“教师模型”指导下的单步或少步模型。
- 提前终止机制:当规划智能体在循环中连续多次调用工具都未能获取新的有效信息时,或答案置信度已达到阈值时,主动终止循环,避免无意义的消耗。
4.2 评估体系构建:如何衡量一个Agent的好坏
传统的检索系统有 MRR、NDCG,生成模型有 BLEU、ROUGE。但 Agent 系统的评估复杂得多,它是一个过程正确性和结果正确性的结合体。我们建立了多维度的评估体系:
- 端到端效果评估(结果导向):
- 人工评测:定期抽样,由专业运营或领域专家从“准确性”、“完整性”、“有用性”、“流畅性”四个维度进行打分。这是黄金标准。
- 基于LLM的自动评测:设计一套提示词,让一个强大的 LLM(如 GPT-4)扮演裁判,根据标准对答案进行评分。虽然不完全可靠,但可以作为高频的自动化辅助手段。
- 过程质量评估(过程导向):
- 工具调用准确率:规划智能体发起的工具调用,有多少比例是相关且必要的?
- 平均推理步数:解决不同类型问题平均需要多少步 ReAct 循环?步数过多可能意味着规划低效。
- 冗余调用率:是否反复调用了相同或相似的工具而未能推进?
- 业务指标关联:
- 问答采纳率/满意率:用户是否点击了“有帮助”?
- 后续行为转化:用户在获得答案后,是否进行了更深度的浏览、加购或咨询?这直接体现了问答的商业价值。
4.3 持续迭代闭环
我们建立了一个基于评估数据的持续迭代闭环:
- 问题收集与归因:从人工评测和用户反馈中收集 bad case。
- 根因分析:每个 bad case 都会回溯完整的 Agent 执行轨迹(思考、行动、观察)。问题可能出在:规划错误(该查的没查)、工具缺陷(查了但没查到或查错)、合成失误(信息理解或组织错误)。
- 针对性优化:
- 规划器优化:如果是规划问题,则丰富提示词、增加示例(few-shot),或在特定场景下添加硬编码规则进行引导。
- 工具优化:如果是工具问题,则优化检索策略、更新数据源、修复工具逻辑。
- 合成器优化:如果是合成问题,则调整合成提示词,或增强矛盾消解模块。
- AB测试与上线:将优化后的版本与基线进行 AB 测试,严格验证效果提升后,再全量发布。
5. 实践反思与未来展望
回顾整个“复合检索 Agent”系统的设计与实践过程,它远非一个简单的技术拼接,而是一次对传统搜索和问答范式的重构。最大的价值在于,它让系统具备了初步的认知和决策能力,能够像人一样,为了解答一个问题而去主动规划、执行、验证。
几点深刻的体会:
- “Agent化”不是银弹,而是架构思维:不是所有场景都需要复杂的 Agent。对于简单、明确的事实性问题,传统的检索增强生成(RAG)管道可能更高效、成本更低。Agent 适用于那些需要多步推理、多源验证、动态决策的复杂问题。关键在于对问题域的准确分析和架构的合理分层。
- 可观测性比功能更重要:一个黑盒的 Agent 系统是可怕的。我们必须记录下每一个智能体的每一次思考、每一次工具调用和结果。这不仅是调试和排错的唯一途径,更是理解系统行为、发现优化点的宝贵数据。我们投入了大量精力建设贯穿全链路的追踪和可视化系统。
- 提示词是“软代码”,需要同等程度的工程化管理:随着系统复杂化,提示词变得庞大且相互关联。我们像管理代码一样,对提示词进行版本控制、模块化拆分、单元测试(用典型用例验证输出格式和逻辑)和代码审查。
- 成本与效果的平衡是永恒的主题:每一步 LLM 的调用都意味着成本和延迟。我们需要精心设计流程,避免不必要的思考循环,用好缓存,并在模型选型上做出务实的选择。“效果提升 10%,成本增加 100%”的方案在商业场景中往往不可行。
未来的演进方向:
- 工具生态的扩展:目前工具以检索和查询为主。未来可以集成更强大的工具,如图像识别(用于根据用户拍的图片回答潮流单品问题)、代码执行器(用于计算复杂的穿搭搭配概率)、甚至外部 API 调用(获取实时天气、赛事信息来推荐穿搭)。
- 记忆与个性化:让 Agent 能够记住与同一用户的对话历史,提供更具连续性和个性化的服务。例如,用户上次询问了跑步鞋,这次问运动袜,Agent 可以主动关联之前的上下文进行推荐。
- 多模态交互:支持用户通过图片、语音等多种方式提问,Agent 也能生成图文并茂、甚至结合短视频片段引用的答案。
- 从“问答”到“任务执行”:当前的 Agent 主要完成信息整合与回答。更进一步的想象是,它可以代理用户执行一些操作,比如“帮我关注这双鞋的价格,低于3000时提醒我”,这就需要 Agent 具备更长期的任务规划和执行能力。
构建复合检索 Agent 系统的旅程,就像训练一位初出茅庐的潮流顾问。它开始可能笨拙、会犯错,但通过清晰的设计、持续的“训练”(数据、提示词、规则)和严格的“考核”(评估体系),它正变得越来越可靠、越来越智能。这条路没有终点,但每一次让系统更准确、更高效地解决用户一个真实问题的时刻,都让我们觉得这一切的复杂和折腾是值得的。