Langchain-Chatchat Agent 对话接口 agent_chat 深度解析:从参数约定到流式工具调用全流程
本篇技术指南围绕 Langchain-Chatchat 项目中的 Agent(代理)对话功能展开,以 markdown_docs/server/chat/agent_chat.md 描述的 agent_chat 及其内部 agent_chat_iterator 为骨架,讲解 Agent 对话接口的核心参数、流式/非流式两种输出模式、LLM 与工具初始化链路,并结合当前仓库源码说明该能力在新版 OpenAI 兼容统一接口中的落地形态。读完你将掌握 Langchain-Chatchat 中「让模型自主规划并调用工具」的对话是如何被编排与返回的,以及如何正确调用与解析这一接口。
Agent 对话(Agent Chat)是 Langchain-Chatchat 中区别于普通 LLM 问答、知识库问答(kb_chat)的一类核心交互:模型不仅生成文本,还会自主决定调用哪些外部工具(天气、搜索、计算、SQL 查询、本地知识库检索等),并根据工具返回结果继续推理,最终给出带工具的最终回答。agent_chat 正是这一能力的对话层封装函数。
一、agent_chat 函数定位与整体职责
文档将 agent_chat 描述为一个异步函数,用于处理用户与 Agent 的聊天对话。它的核心职责可以拆解为四个阶段:
- 历史规范化:把传入的历史对话列表
history统一转换为History对象列表,保证后续构造模型消息时格式一致; - 迭代器定义:在函数内部定义异步迭代器
agent_chat_iterator,真正承载"初始化模型与工具 → 处理历史 → 驱动 Agent 推理 → 产出回复"的完整链路; - 流式/非流式分发:当
stream=True时以异步yield逐块吐出 JSON 数据(适用于聊天框实时刷新场景);否则收集全部输出后一次性组装为一个 JSON 响应体返回; - 状态感知输出:在流式模式下,会根据 Agent 运行的不同阶段(工具调用开始、完成、出错、得到最终答案等)产出不同结构的 JSON 数据块。
从当前仓库的服务端目录看,Agent 对话不再以独立模块存在:server/chat/ 目录下仅保留 chat.py、completion.py、feedback.py、file_chat.py、human_message_event.py、kb_chat.py、utils.py,Agent 对话能力已被整合进 chat_routes.py 的 OpenAI 兼容统一对话接口(详见下文第六节),因此本文档描述的 agent_chat 更应被理解为一份接口行为规范,其参数语义与输出格式约定至今仍然有效。
二、核心参数说明
agent_chat 对外暴露的参数决定了 Agent 对话的每一次行为,是接入方最需要关心的部分:
| 参数 | 类型与必填 | 含义与默认值 |
|---|---|---|
query |
字符串,必填 | 用户输入的查询语句,是驱动 Agent 推理的起点 |
history |
列表 | 历史对话记录,每个元素为一个 History 对象;传入前需保证元素要么本身就是 History,要么可被转换为 History |
stream |
布尔,默认 False |
是否以流式方式返回数据;True 适合需要实时更新聊天气泡的场景 |
model_name |
字符串 | 使用的 LLM 模型名称,默认取 LLM_MODELS 配置列表中的第一个模型 |
temperature |
浮点 | LLM 采样温度,控制生成随机性,取值范围 0.0~1.0,默认值由运行时 TEMPERATURE 配置决定 |
max_tokens |
整数/None,默认 None |
限制生成 Token 数上限;None 表示不设限制、使用模型自身最大值 |
prompt_name |
字符串,默认 "default" |
选用的 Prompt 模板名称,agent_chat 依据它加载对应提示模板 |
值得注意的两点参数语义:
temperature与max_tokens是"一次请求级"的覆盖开关。它们默认值来自运行时配置(TEMPERATURE、LLM 模型最大上下文),但调用方每次都可以显式传入覆盖值。Agent 在调用工具时需要模型输出结构化的 Action JSON,过高的temperature会降低输出格式稳定性,实际调优时通常建议对 Agent 推理保持较低温度。model_name的默认取首个模型而非 Agent 专属模型。文档同时说明:如果运行时配置了Agent_MODEL,内部会额外用该模型初始化一个"Agent 大脑",并将其单独挂入模型容器——这为"Agent 规划模型"与"普通问答模型"分离提供了设计空间。
三、内部执行链路 agent_chat_iterator 逐段拆解
文档指出 agent_chat_iterator 是异步生成器,其内部编排逻辑分为多个关键步骤,下面结合文档与当前仓库源码逐段说明。
1. max_tokens 防御性归一化
进入循环前首先检查:若 max_tokens 是整数且 <= 0,则将其重置为 None。这样可避免传入 0 或负数导致模型侧 Token 限制异常,属于健壮性兜底。
2. 模型与工具上下文初始化
- 通过
get_ChatOpenAI初始化主聊天模型实例; - 调用
get_kb_details获取知识库列表详情,注入模型容器(model_container)的数据库字段,使 Agent 在需要时可感知"有哪些知识库可用"(对应"检索本地知识库"类工具); - 若配置了
Agent_MODEL,则用该模型再初始化一个独立聊天模型实例并同样放入容器;否则复用前面初始化的主模型。
3. Prompt 模板与输出解析器装配
get_prompt_template依据prompt_name取出模板内容;- 用
CustomPromptTemplate实例化自定义 Prompt 模板,用于把"可用工具描述 + 历史对话 + 当前问题"渲染为发给 LLM 的完整指令; - 用
CustomOutputParser创建输出解析器,负责把模型吐出的文本解析成结构化 Agent 动作。
这套"模板渲染 + 输出解析"的经典 Agent 架构,在当前仓库中被重构并下沉到 langchain_chatchat/agents 下,面向不同模型家族提供了多种解析器与模板工厂:
- 模型家族输出解析器:structured_chat_output_parsers.py、glm3_output_parsers.py、qwen_output_parsers.py 等,分别对应通用、GLM3、Qwen 等模型的 Action 解析规则;
- 平台工具类解析:
platform_tools.py、platform_knowledge_output_parsers.py负责把模型消息中的 tool call 与函数调用解析为 Agent 动作; - Prompt 模板工厂:react/create_prompt_template.py 提供
create_prompt_glm3_template、create_prompt_structured_react_template、create_prompt_gpt_tool_template、create_prompt_platform_knowledge_mode_template等,分别面向不同 Agent 执行范式(ReAct、GPT Function Calling、知识库增强模式等)。
4. Agent 执行器创建与异步驱动
旧文档描述:根据模型名称,若为 GLM3 则调用 initialize_glm3_agent 初始化专用 Agent 执行器,否则基于 LLMSingleActionAgent + AgentExecutor 组装通用执行器。这正是 Langchain-Chatchat 早期对 ChatGLM 函数调用格式做专项适配的体现。
从当前仓库结构看,该逻辑已升级为"按 Agent 类型注册 + 统一创建"的机制:
- server/agents_registry/agents_registry.py 负责 Agent 执行器类型的注册与分发;
- langchain_chatchat/agents/all_tools_agent.py 承载统一工具型 Agent 的动作执行(
_acall/_aperform_agent_action等); - 按模型与范式区分的创建函数集中在 agents/structured_chat 下,例如
create_structured_glm3_chat_agent、create_chat_agent、create_platform_tools_agent等,分别对应 ChatGLM3 结构化、通用 ReAct、平台工具绑定等执行风格。
5. wrap_done 回调与异步产出
在异步循环中,Agent 执行器的运行会被包装成一个 asyncio 任务,用 wrap_done 绑定完成事件——任务结束即通过回调通知唤醒等待方,避免异步死锁。这一惯用封装在当前版本中仍保留于 Agent 工具包的公共基类中(位于 agent_toolkits/all_tools 下,定义 wrap_done(fn, event))。
之后分两条路径输出:
stream=True:异步迭代回调处理器(文档中的CustomAsyncIteratorCallbackHandler)的缓存输出,依据当前 Agent 状态把日志/中间步聚/最终回答编码为 JSON 块并yield;stream=False:在循环内累积全部输出,结束后一次性yield一个同时含answer与final_answer的完整 JSON 对象。
四、返回格式约定:非流式与流式
1. 非流式输出
当请求未开启流式且用户查询最终生成了一系列回复时,函数返回如下结构的 JSON:
{
"answer": "这是聊天过程中生成的回复文本。",
"final_answer": "这是最终的回复文本。"
}
其中 answer 记录聊天过程中累计生成的回复文本,final_answer 则是经过完整推理(含工具调用后的收敛)产出的最终答案。接入方在非流式模式下只需等待接口整体返回并读取 final_answer 即可。
2. 流式输出
流式模式下函数逐块返回数据,前端可按"状态字段"增量渲染。典型的数据块分为两类。
第一类:工具调用过程块,携带本次工具名称、状态、输入与输出,供前端渲染"正在调用工具"的过程日志:
{
"tools": [
"工具名称: 天气查询",
"工具状态: 调用成功",
"工具输入: 北京今天天气",
"工具输出: 北京今天多云,10-14摄氏度"
]
}
第二类:最终回答块,当 Agent 完成全部推理后下发:
{
"final_answer": "这是最终的回复文本。"
}
从当前仓库的工具类型定义可以印证这类过程信息的结构设计:在 langchain_chatchat/agents/output_parsers/tools_output 目录下,分别针对普通函数工具(function.py)、代码解释器(code_interpreter.py)、画图工具(drawing_tool.py)、网页浏览工具(web_browser.py)定义了各自的 AgentAction 流式解析逻辑,说明"工具名称、输入、中间输出"作为 Agent 对话的流式中间事件被系统化建模。调用方在解析流时,应区分"过程事件块"与"终止回答块",前者做过程展示、后者做最终内容渲染并结束会话。
五、从接口文档到当前仓库的落地形态
如前所述,当前仓库已将 Agent 对话收敛到 chat_routes.py 定义的 /chat/completions 统一接口中。其请求解析规则与 agent_chat 的定位一脉相承:
- 请求的
extra_body中含tool_input:视为对某个工具的直接调用(tool_choice); - 请求的
extra_body中含tool_choice但不含tool_input:通过 Agent 推理决定如何调用该工具; - 请求中带
tools列表:进入 Agent 对话模式,由模型自主规划工具; - 其他情况:普通 LLM 对话。
也就是说,新版中"是否携带工具声明"即等价于旧文档 agent_chat 与普通 chat 的分界。该路由在把消息落库时明确记录了 chat_type="agent_chat"(见 chat_routes.py),与知识库对话(kb_chat)、文件对话(file_chat)在历史消息维度上被区分为不同类型的会话,便于后续按类型回放与统计。
支撑 Agent 对话的工具生态则沉淀在 server/agent/tools_factory/tools_registry.py 与同目录的工具实现中,包括天气查询(amap_weather.py)、高德 POI 搜索(amap_poi_search.py)、通用互联网搜索(search_internet.py)、本地知识库检索(search_local_knowledgebase.py)、计算器(calculate.py)、SQL 查询(text2sql.py)、PROMQL 查询(text2promql.py)、文生图(text2image.py)、URL 读取(url_reader.py)等,它们共同构成 Agent 可自主调用的工具集。
六、使用注意事项与最佳实践
文档明确提示了以下使用边界,结合实践可进一步展开:
history必须格式合法:每个元素应为History对象,或至少是能够被转换为History的数据结构,否则消息构造会失败。接入方建议在会话层统一维护 History 序列,不混用字符串与对象。stream决定返回方式,需与前端配套:流式模式返回的是多段 JSON 事件流,前端要按事件类型分别渲染过程与结果;非流式模式则一次性返回完整对象。二者不能混用解析逻辑。- 依赖项须预先配置:
agent_chat强依赖已配置的 LLM 模型、工具注册与 Prompt 模板,调用前应确保模型服务(对应LLM_MODELS首模型或Agent_MODEL)可用,否则 Agent 无法进入规划环节。 prompt_name与模型能力匹配:不同模型家族(GLM3 / Qwen / 通用 OpenAI 兼容)对工具调用的指令遵循格式不同,应选用与其输出解析器匹配的模板与执行器类型。- 生产建议:对 Agent 会话适当调低
temperature以保证 Action 输出格式稳定;max_tokens设置过小会导致推理在工具调用中途被截断,一般交给模型默认最大值,仅在确有上下文预算约束时收紧。
七、小结
agent_chat 是理解 Langchain-Chatchat Agent 对话语义的钥匙:它以 query 为输入、以"模型 + 工具 + 模板 + 解析器"为推理内核,通过 stream 开关对外提供事件流与整体响应两种消费方式,并用 answer/final_answer、tools 等结构化字段把"过程"与"结果"清晰暴露给调用方。即便其底层实现在当前仓库中已重构并入 OpenAI 兼容的 /chat/completions(以 tools 是否存在判定 Agent 模式),本文所解析的参数语义、内部执行链路与输出格式约定,依然是理解并接入这一能力最直接的参考——建议配合 agent_chat.md、chat_routes.py 以及 agents 目录 下的解析器与模板工厂源码对照阅读。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00