智能客户服务协助智能体
<style>pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; line-height: 1.6 !important; padding: 16px !important; margin: 16px 0 !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; tab-size: 4 !important; -moz-tab-size: 4 !important; max-width: 100% !important; box-sizing: border-box !important }code { font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow-wrap: normal !important; display: inline !important; background: rgba(0, 0, 0, 0) !important; border: none !important; padding: 0 !important; margin: 0 !important; line-height: inherit !important }
pre code { background: rgba(0, 0, 0, 0) !important; border: 0 !important; border-radius: 0 !important; display: block !important; line-height: 1.6 !important; margin: 0 !important; max-width: none !important; overflow: visible !important; padding: 0 !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; color: inherit !important }
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: rgba(112, 128, 144, 1) !important; font-style: italic !important }
.token.punctuation { color: rgba(153, 153, 153, 1) !important }
.token.atrule, .token.attr-value, .token.keyword { color: rgba(0, 119, 170, 1) !important; font-weight: bold !important }
.token.function, .token.class-name { color: rgba(221, 74, 104, 1) !important; font-weight: bold !important }
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: rgba(102, 153, 0, 1) !important }
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: rgba(153, 0, 85, 1) !important }
.cnblogs-markdown pre, .cnblogs-post-body pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; padding: 16px !important; margin: 16px 0 !important }
pre, pre, pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important }</style>
<style>pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; line-height: 1.6 !important; padding: 16px !important; margin: 16px 0 !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; tab-size: 4 !important; -moz-tab-size: 4 !important; max-width: 100% !important; box-sizing: border-box !important }
code { font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow-wrap: normal !important; display: inline !important; background: rgba(0, 0, 0, 0) !important; border: none !important; padding: 0 !important; margin: 0 !important; line-height: inherit !important }
pre code { background: rgba(0, 0, 0, 0) !important; border: 0 !important; border-radius: 0 !important; display: block !important; line-height: 1.6 !important; margin: 0 !important; max-width: none !important; overflow: visible !important; padding: 0 !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; color: inherit !important }
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: rgba(112, 128, 144, 1) !important; font-style: italic !important }
.token.punctuation { color: rgba(153, 153, 153, 1) !important }
.token.atrule, .token.attr-value, .token.keyword { color: rgba(0, 119, 170, 1) !important; font-weight: bold !important }
.token.function, .token.class-name { color: rgba(221, 74, 104, 1) !important; font-weight: bold !important }
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: rgba(102, 153, 0, 1) !important }
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: rgba(153, 0, 85, 1) !important }
.cnblogs-markdown pre, .cnblogs-post-body pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; padding: 16px !important; margin: 16px 0 !important }
pre, pre, pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important }</style><div class="markdown_views prism-atom-one-dark" id="content_views"><svg style="display: none" xmlns="http://www.w3.org/2000/svg"><path d="M5,0 0,2.5 5,5z" id="raphael-marker-block" stroke-linecap="round" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0)"></path></svg><p>超越传统客服机器人。智能体可以深度查询知识库、调用订单系统API、甚至根据客户情绪灵活处理退货、退款、升级投诉等复杂流程。</p><p>案例:</p><p>客户说:“我上周买的鞋子尺码不对,想换货但是找不到订单页面了。”</p><p>智能体行动: ① 通过用户身份验证;② 调用订单查询API找到该订单;③ 检查换货政策;④ 生成换货链接并指导用户下一步操作;⑤ 若流程中断,后续可主动发送邮件提醒。</p><p><strong>1. 核心功能</strong></p><ul><li>多轮对话与上下文理解:能理解并记忆对话上下文。</li><li>工具调用(Tool Use):能调用外部API获取真实数据(如订单、用户信息)。</li><li>知识库检索(RAG):能从企业知识库(如手册、FAQ)中检索精准信息。</li><li>安全性与权限控制:验证用户身份,并基于身份控制数据访问范围</li><li>人工接管(Human-in-the-loop):在无法处理或用户要求时,无缝转接人工客服</li></ul><p><strong>2. 技术栈选择(企业级)</strong></p><ul><li><p>LLM(大脑): OpenAI GPT-4 Turbo (性价比和性能平衡)</p></li><li><p>开发框架: LangChain / LangGraph (用于构建复杂、有状态的智能体工作流)</p></li><li><p>工具调用: LangChain Tools & Custom Functions</p></li><li><p>知识库: Chroma (向量数据库,轻量且高效) + OpenAI Embeddings</p></li><li><p>后端API: FastAPI (高性能、异步支持好,适合生产环境)</p></li><li><p>身份认证: JWT Tokens</p></li><li><p>数据持久化: SQL Database (PostgreSQL) for logging</p></li><li><p>部署: Docker & Kubernetes (容器化便于扩展和管理)</p></li></ul><p><strong>架构设计</strong><br><img src="https://i-blog.csdnimg.cn/direct/ff1bf67fd1be4e4698c1ebd8cb2fafaa.png#pic_center"><br><img src="https://i-blog.csdnimg.cn/direct/6165102d2e2d4a20936a631c63dd02f8.png#pic_center"></p><h3>一、环境依赖</h3>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token comment"># 创建项目目录并初始化虚拟环境</span>
<span class="token function">mkdir</span> customer-support-agent
<span class="token builtin class-name">cd</span> customer-support-agent
python -m venv venv
<span class="token builtin class-name">source</span> venv/bin/activate <span class="token comment"># Linux/Mac</span>
<span class="token comment"># venv\Scripts\activate # Windows</span>
<span class="token comment"># 安装核心依赖</span>
pip <span class="token function">install</span> openai langchain langgraph chromadb langchain-openai fastapi uvicorn python-jose<span class="token punctuation">[</span>cryptography<span class="token punctuation">]</span> passlib sqlalchemy psycopg2-binary pydantic</code></pre>
<h3>二、数据模型</h3><p>models.py</p><ul><li>UserIdentity - 用户身份标识,跟踪用户身份和会话信息</li><li>AgentState - 智能体状态管理,管理对话智能体的完整状态,这是LangGraph框架中的核心概念</li><li>ConversationType - 对话类型枚举,定义对话的意图分类,限制可能的对话类型,便于处理后续的统计分析和逻辑分支</li><li>ConversationLog - 对话日志存储:用于持久化存储对话记录到数据库</li></ul>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-py"><span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel<span class="token punctuation">,</span> Field <span class="token comment">#Pydantic: 提供数据验证和设置管理的现代Python数据验证库</span>
<span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional<span class="token punctuation">,</span> List<span class="token punctuation">,</span> Dict<span class="token punctuation">,</span> Any <span class="token comment">#typing: 用于类型注解,提高代码可读性和类型安全</span>
<span class="token keyword">from</span> enum <span class="token keyword">import</span> Enum <span class="token comment">#enum: 用于定义枚举类型,限制可能的取值</span>
<span class="token keyword">class</span> <span class="token class-name">UserIdentity</span>
<span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""用户身份标识"""</span>
user_id<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token comment">#user_id: 可选字段,用于已登录用户</span>
session_id<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token comment">#session_id: 必需字段,唯一标识一个对话会话</span>
is_authenticated<span class="token punctuation">:</span> <span class="token builtin">bool</span> <span class="token operator">=</span> <span class="token boolean">False</span> <span class="token comment">#is_authenticated: 标识用户是否通过身份验证</span>
<span class="token keyword">class</span> <span class="token class-name">AgentState</span>
<span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""LangGraph智能体的状态"""</span>
<span class="token comment">#一个列表,列表中的每个元素都是字典,使用Field类来定义字段的详细配置,...表示该字段是必需的,不能为空</span>
messages<span class="token punctuation">:</span> List<span class="token punctuation">[</span>Dict<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">,</span> Any<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"对话消息历史"</span><span class="token punctuation">)</span>
user_identity<span class="token punctuation">:</span> UserIdentity <span class="token operator">=</span> Field<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"用户身份信息"</span><span class="token punctuation">)</span>
current_step<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span><span class="token string">"greeting"</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"当前对话步骤"</span><span class="token punctuation">)</span><span class="token comment">#"greeting": 默认值,表示如果没有提供值,就使用这个默认值</span>
<span class="token comment">#default_factory=dict: 使用工厂函数,每次创建新实例时都会调用dict()创建一个新的空字典</span>
extracted_info<span class="token punctuation">:</span> Dict<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">,</span> Any<span class="token punctuation">]</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span>default_factory<span class="token operator">=</span><span class="token builtin">dict</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"从对话中提取的结构化信息"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">ConversationType</span>
<span class="token punctuation">(</span>Enum<span class="token punctuation">)</span><span class="token punctuation">:</span>
QUERY_ORDER <span class="token operator">=</span> <span class="token string">"query_order"</span> <span class="token comment"># 订单查询</span>
RETURN_EXCHANGE <span class="token operator">=</span> <span class="token string">"return_exchange"</span> <span class="token comment"># 退换货</span>
GENERAL_QUESTION <span class="token operator">=</span> <span class="token string">"general_question"</span> <span class="token comment"># 一般问题</span>
<span class="token keyword">class</span> <span class="token class-name">ConversationLog</span>
<span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""存入数据库的对话日志"""</span>
session_id<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token comment"># 会话标识</span>
user_id<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token comment"># 可选用户ID</span>
message<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token comment"># 用户消息内容</span>
agent_response<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token comment"># 智能体回复内容</span>
intent<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token comment"># 识别出的意图</span>
timestamp<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token comment"># 时间戳</span>
success<span class="token punctuation">:</span> <span class="token builtin">bool</span> <span class="token comment"># 处理是否成功</span></code></pre>
<p>画外题:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-py"><span class="token comment">#创建实例</span>
state <span class="token operator">=</span> AgentState<span class="token punctuation">(</span>
messages<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">{</span>
<span class="token string">"role"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token string">"content"</span><span class="token punctuation">:</span> <span class="token string">"你好"</span>
<span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
user_identity<span class="token operator">=</span>UserIdentity<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment"># 需要提供UserIdentity实例</span>
<span class="token comment"># current_step 使用默认值 "greeting"</span>
<span class="token comment"># extracted_info 使用默认空字典</span>
<span class="token punctuation">)</span>
<span class="token comment"># 访问属性</span>
<span class="token keyword">print</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>current_step<span class="token punctuation">)</span> <span class="token comment"># 输出: "greeting"</span>
<span class="token keyword">print</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>extracted_info<span class="token punctuation">)</span> <span class="token comment"># 输出: {}</span></code></pre>
<p><img src="https://i-blog.csdnimg.cn/direct/97dc52bef30546d89a22b77a2123c0f5.png#pic_center"></p><h3>三、核心工具</h3><p>tools.py</p><ul><li>订单查询工具→ AI调用query_order_tool</li><li>退换货政策查询工具→ AI调用query_return_policy_tool</li><li>复杂问题无法解决 → AI调用create_support_ticket_tool</li></ul>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-py"><span class="token keyword">import</span> requests
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>tools <span class="token keyword">import</span> tool <span class="token comment">#LangChain的工具装饰器,将函数转换为AI可调用的工具</span>
<span class="token keyword">from</span> typing <span class="token keyword">import</span> Type
<span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel<span class="token punctuation">,</span> Field
<span class="token keyword">import</span> os
<span class="token comment"># 1. 订单查询工具</span>
<span class="token keyword">class</span> <span class="token class-name">OrderQueryInput</span>
<span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span>
order_id<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"The order ID to query"</span><span class="token punctuation">)</span>
<span class="token comment">#装饰器是一种高级功能,它允许在不修改原函数代码的情况下,为函数添加额外的功能。</span>
<span class="token comment">#将一个普通的 Python 函数"包装"成一个可以被 AI 大语言模型(LLM)识别和调用的工具(Tool)</span>
<span class="token comment">#(args_schema=OrderQueryInput):这是传递给 @tool 装饰器的参数,定义了工具输入参数的名称、类型、描述等,帮助 AI 模型理解如何正确地调用这个函数。</span>
<span class="token decorator annotation punctuation">@tool</span><span class="token punctuation">(</span>args_schema<span class="token operator">=</span>OrderQueryInput<span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">query_order_tool</span><span class="token punctuation">(</span>order_id<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
<span class="token builtin">str</span><span class="token punctuation">:</span> <span class="token comment"># -> str::返回类型提示,表明这个函数执行完毕后会返回一个字符串(String)类型的结果</span>
<span class="token triple-quoted-string string">"""
查询用户订单信息。需要先验证用户身份。
"""</span>
<span class="token comment"># 模拟调用内部订单系统API</span>
<span class="token comment"># 真实环境中,这里会是 requests.get(f"{ORDER_API_URL}/{order_id}", headers=...)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" Querying order: </span><span class="token interpolation"><span class="token punctuation">{</span>order_id
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 模拟响应 创建字典 构建了一个订单对象的详细信息,包括产品、尺寸、日期、状态</span>
mock_order_data <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">"order_id"</span><span class="token punctuation">:</span> order_id<span class="token punctuation">,</span>
<span class="token string">"product"</span><span class="token punctuation">:</span> <span class="token string">"Running Shoes (Model X)"</span><span class="token punctuation">,</span>
<span class="token string">"size"</span><span class="token punctuation">:</span> <span class="token string">"42"</span><span class="token punctuation">,</span>
<span class="token string">"order_date"</span><span class="token punctuation">:</span> <span class="token string">"2024-09-15"</span><span class="token punctuation">,</span>
<span class="token string">"status"</span><span class="token punctuation">:</span> <span class="token string">"Delivered"</span><span class="token punctuation">,</span>
<span class="token string">"customer_id"</span><span class="token punctuation">:</span> <span class="token string">"cust_12345"</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f"Order Details: </span><span class="token interpolation"><span class="token punctuation">{</span>
<span class="token builtin">str</span><span class="token punctuation">(</span>mock_order_data<span class="token punctuation">)</span>
<span class="token punctuation">}</span></span><span class="token string">"</span></span>
<span class="token comment"># 2. 退换货政策查询工具 (RAG)</span>
<span class="token decorator annotation punctuation">@tool</span> <span class="token comment"># @tool 装饰器告诉AI框架:“这个函数是我(AI)可以用的一个工具”。</span>
<span class="token keyword">def</span> <span class="token function">query_return_policy_tool</span><span class="token punctuation">(</span>product_category<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
<span class="token builtin">str</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""
根据产品类别查询退换货政策。如果用户未指定类别,则查询通用政策。
"""</span>
<span class="token comment"># 在真实环境中,这里会从向量数据库检索</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" Querying return policy for: </span><span class="token interpolation"><span class="token punctuation">{</span>product_category
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
policies <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">"general"</span><span class="token punctuation">:</span> <span class="token string">"You can return most items within 30 days of delivery. Items must be unworn and in original packaging."</span><span class="token punctuation">,</span>
<span class="token string">"shoes"</span><span class="token punctuation">:</span> <span class="token string">"Shoes can be exchanged for a different size within 45 days. Must have original box and no signs of wear."</span><span class="token punctuation">,</span>
<span class="token string">"electronics"</span><span class="token punctuation">:</span> <span class="token string">"Electronics can be returned within 14 days. Must be factory reset and all accessories included."</span>
<span class="token punctuation">}</span>
policy <span class="token operator">=</span> policies<span class="token punctuation">.</span>get<span class="token punctuation">(</span>product_category<span class="token punctuation">.</span>lower<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> policies<span class="token punctuation">[</span><span class="token string">"general"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f"Our return policy for </span><span class="token interpolation"><span class="token punctuation">{</span>product_category
<span class="token punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token punctuation">{</span>policy
<span class="token punctuation">}</span></span><span class="token string">"</span></span>
<span class="token comment"># 3. 创建客服工单工具</span>
<span class="token keyword">class</span> <span class="token class-name">CreateTicketInput</span>
<span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span>
issue_summary<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"A summary of the customer's issue"</span><span class="token punctuation">)</span>
priority<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> Field<span class="token punctuation">(</span><span class="token string">"medium"</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"Priority of the ticket: low, medium, high"</span><span class="token punctuation">)</span>
<span class="token decorator annotation punctuation">@tool</span><span class="token punctuation">(</span>args_schema<span class="token operator">=</span>CreateTicketInput<span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">create_support_ticket_tool</span><span class="token punctuation">(</span>issue_summary<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">,</span> priority<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> <span class="token string">"medium"</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
<span class="token builtin">str</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""
在第三方系统(如Zendesk、Jira)中创建支持工单。用于当智能体无法解决问题时。
"""</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" Creating Support Ticket. Priority: </span><span class="token interpolation"><span class="token punctuation">{</span>priority
<span class="token punctuation">}</span></span><span class="token string">. Issue: </span><span class="token interpolation"><span class="token punctuation">{</span>issue_summary
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 模拟创建工单的API调用</span>
ticket_id <span class="token operator">=</span> <span class="token string">"TICKET-0987"</span>
<span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f"Successfully created a support ticket for you. Your ticket ID is </span><span class="token interpolation"><span class="token punctuation">{</span>ticket_id
<span class="token punctuation">}</span></span><span class="token string">. A human agent will contact you shortly."</span></span></code></pre>
<p>生产环境改进建议</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-py"><span class="token keyword">def</span> <span class="token function">query_order_tool</span><span class="token punctuation">(</span>order_id<span class="token punctuation">:</span><span class="token builtin">str</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
<span class="token builtin">str</span><span class="token punctuation">:</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
response <span class="token operator">=</span> requests<span class="token punctuation">.</span>get<span class="token punctuation">(</span>
<span class="token string">r"{os.getenv('ORDER_API_URL')}/{order_id}"</span><span class="token punctuation">,</span>
headers <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">"Authorization"</span><span class="token punctuation">:</span> <span class="token string-interpolation"><span class="token string">f"Bearer </span><span class="token interpolation"><span class="token punctuation">{</span>os<span class="token punctuation">.</span>getenv<span class="token punctuation">(</span><span class="token string">'API_TOKEN'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></span><span class="token string">"</span></span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
timeout <span class="token operator">=</span> <span class="token number">10</span>
<span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f"Order Details:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">.</span>json<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></span><span class="token string">"</span></span>
<span class="token keyword">except</span> requests<span class="token punctuation">.</span>RequestException <span class="token keyword">as</span> e<span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f"Sorry, I couldn't retrieve your order details. Error: </span><span class="token interpolation"><span class="token punctuation">{</span>
<span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span>
<span class="token punctuation">}</span></span><span class="token string">"</span></span></code></pre>
<h3>四、构建智能体工作流</h3>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-txt">+-------------+
| agent |# 决策节点
+-------------+
|
v (条件路由)
+---------+---------+
| | |
v v v
+-------+ END +-------------+
| tools | | human_agent |
+-------+ +-------------+
| |
+--------+ |
v v
+-------------+
| agent |# 循环回到agent
+-------------+</code></pre>
<p>agent.py</p><ul><li>智能体决策节点,接收当前对话状态,调用LLM会自动决定是否需要调用工具,返回AI消息到状态中</li><li>路由函数 - 核心决策逻辑</li></ul>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-py"><span class="token keyword">from</span> langgraph<span class="token punctuation">.</span>graph <span class="token keyword">import</span> StateGraph<span class="token punctuation">,</span> END
<span class="token keyword">from</span> langgraph<span class="token punctuation">.</span>prebuilt <span class="token keyword">import</span> ToolNode
<span class="token keyword">from</span> langchain_core<span class="token punctuation">.</span>messages <span class="token keyword">import</span> HumanMessage<span class="token punctuation">,</span> AIMessage<span class="token punctuation">,</span> ToolMessage
<span class="token keyword">from</span> langchain_openai <span class="token keyword">import</span> ChatOpenAI
<span class="token keyword">from</span> models <span class="token keyword">import</span> AgentState
<span class="token keyword">from</span> tools <span class="token keyword">import</span> query_order_tool<span class="token punctuation">,</span> query_return_policy_tool<span class="token punctuation">,</span> create_support_ticket_tool
<span class="token keyword">from</span> typing <span class="token keyword">import</span> Literal<span class="token punctuation">,</span> Dict<span class="token punctuation">,</span> Any
<span class="token comment"># 初始化LLM</span>
llm <span class="token operator">=</span> ChatOpenAI<span class="token punctuation">(</span>model<span class="token operator">=</span><span class="token string">"gpt-4-turbo"</span><span class="token punctuation">,</span> temperature<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment">#模型选择: gpt-4-turbo 提供强大的推理能力 温度设置: temperature=0 确保确定性输出,适合客服场景</span>
<span class="token comment"># 绑定工具 工具绑定: bind_tools() 让LLM知道可用的工具及其功能</span>
llm_with_tools <span class="token operator">=</span> llm<span class="token punctuation">.</span>bind_tools<span class="token punctuation">(</span><span class="token punctuation">[</span>query_order_tool<span class="token punctuation">,</span> query_return_policy_tool<span class="token punctuation">,</span> create_support_ticket_tool<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token comment"># 定义工具节点 ToolNode 专门处理工具调用的执行</span>
tool_node <span class="token operator">=</span> ToolNode<span class="token punctuation">(</span>tools<span class="token operator">=</span><span class="token punctuation">[</span>query_order_tool<span class="token punctuation">,</span> query_return_policy_tool<span class="token punctuation">,</span> create_support_ticket_tool<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">agent_step</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> AgentState<span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token comment">#接收当前对话状态</span>
<span class="token triple-quoted-string string">"""智能体决策节点"""</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" Current Step: </span><span class="token interpolation"><span class="token punctuation">{</span>state<span class="token punctuation">[</span><span class="token string">'current_step'</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
messages <span class="token operator">=</span> state<span class="token punctuation">[</span><span class="token string">"messages"</span><span class="token punctuation">]</span>
response <span class="token operator">=</span> llm_with_tools<span class="token punctuation">.</span>invoke<span class="token punctuation">(</span>messages<span class="token punctuation">)</span> <span class="token comment">#调用LLM生成响应,LLM会自动决定是否需要调用工具</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span>
<span class="token string">"messages"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>response<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token comment"># 返回AI消息到状态中</span>
<span class="token keyword">def</span> <span class="token function">route_to_tools</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> AgentState<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> Literal<span class="token punctuation">[</span><span class="token string">"tools"</span><span class="token punctuation">,</span> <span class="token string">"end"</span><span class="token punctuation">,</span> <span class="token string">"human_agent"</span><span class="token punctuation">]</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""路由函数,决定下一步是调用工具、结束还是转人工"""</span>
ai_msg <span class="token operator">=</span> state<span class="token punctuation">[</span><span class="token string">"messages"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span>
<span class="token comment">#检查工具调用: 如果AI消息包含tool_calls,转到"tools"节点</span>
<span class="token keyword">if</span> <span class="token keyword">not</span> <span class="token builtin">hasattr</span><span class="token punctuation">(</span>ai_msg<span class="token punctuation">,</span> <span class="token string">'tool_calls'</span><span class="token punctuation">)</span> <span class="token keyword">or</span> <span class="token builtin">len</span><span class="token punctuation">(</span>ai_msg<span class="token punctuation">.</span>tool_calls<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">:</span>
<span class="token comment"># 如果没有工具调用,检查是否需要结束或转人工</span>
<span class="token keyword">if</span> <span class="token string">"thank you"</span> <span class="token keyword">in</span> state<span class="token punctuation">[</span><span class="token string">"messages"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">.</span>lower<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token comment">#结束条件: 用户说"thank you"时结束对话</span>
<span class="token keyword">return</span> <span class="token string">"end"</span>
<span class="token keyword">if</span> <span class="token string">"human"</span> <span class="token keyword">in</span> state<span class="token punctuation">[</span><span class="token string">"messages"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">.</span>lower<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token string">"human_agent"</span>
<span class="token keyword">return</span> <span class="token string">"end"</span>
<span class="token keyword">return</span> <span class="token string">"tools"</span>
<span class="token keyword">def</span> <span class="token function">call_human_agent</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> AgentState<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""调用创建工单工具并结束对话"""</span>
issue_summary <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"Customer requested human agent. Conversation history: </span><span class="token interpolation"><span class="token punctuation">{</span>state<span class="token punctuation">[</span><span class="token string">'messages'</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span></span><span class="token string">"</span></span>
tool_input <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">"issue_summary"</span><span class="token punctuation">:</span> issue_summary<span class="token punctuation">,</span> <span class="token string">"priority"</span><span class="token punctuation">:</span> <span class="token string">"medium"</span>
<span class="token punctuation">}</span>
result <span class="token operator">=</span> create_support_ticket_tool<span class="token punctuation">.</span>invoke<span class="token punctuation">(</span>tool_input<span class="token punctuation">)</span><span class="token comment">#返回友好的转接消息</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span>
<span class="token string">"messages"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>AIMessage<span class="token punctuation">(</span>content<span class="token operator">=</span><span class="token string-interpolation"><span class="token string">f"I've escalated your issue to our human team. </span><span class="token interpolation"><span class="token punctuation">{</span>result
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>
<span class="token comment"># 构建图</span>
workflow <span class="token operator">=</span> StateGraph<span class="token punctuation">(</span>AgentState<span class="token punctuation">)</span>
workflow<span class="token punctuation">.</span>add_node<span class="token punctuation">(</span><span class="token string">"agent"</span><span class="token punctuation">,</span> agent_step<span class="token punctuation">)</span>
workflow<span class="token punctuation">.</span>add_node<span class="token punctuation">(</span><span class="token string">"tools"</span><span class="token punctuation">,</span> tool_node<span class="token punctuation">)</span>
workflow<span class="token punctuation">.</span>add_node<span class="token punctuation">(</span><span class="token string">"human_agent"</span><span class="token punctuation">,</span> call_human_agent<span class="token punctuation">)</span>
workflow<span class="token punctuation">.</span>set_entry_point<span class="token punctuation">(</span><span class="token string">"agent"</span><span class="token punctuation">)</span>
workflow<span class="token punctuation">.</span>add_conditional_edges<span class="token punctuation">(</span>
<span class="token string">"agent"</span><span class="token punctuation">,</span>
route_to_tools<span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"tools"</span><span class="token punctuation">:</span> <span class="token string">"tools"</span><span class="token punctuation">,</span>
<span class="token string">"end"</span><span class="token punctuation">:</span> END<span class="token punctuation">,</span>
<span class="token string">"human_agent"</span><span class="token punctuation">:</span> <span class="token string">"human_agent"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span>
workflow<span class="token punctuation">.</span>add_edge<span class="token punctuation">(</span><span class="token string">"tools"</span><span class="token punctuation">,</span> <span class="token string">"agent"</span><span class="token punctuation">)</span>
workflow<span class="token punctuation">.</span>add_edge<span class="token punctuation">(</span><span class="token string">"human_agent"</span><span class="token punctuation">,</span> END<span class="token punctuation">)</span>
<span class="token comment"># 编译图</span>
app <span class="token operator">=</span> workflow<span class="token punctuation">.</span><span class="token builtin">compile</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p>实际对话示例:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-text">用户: "我想查询订单12345"
AI: (决定调用query_order_tool) → 工具节点 → 返回结果
用户: "谢谢你的帮助"
AI: (检测到感谢) → 结束对话
用户: "我要找人工客服"
AI: (检测到"human") → 转人工节点 → 创建工单 → 结束</code></pre>
<h3>五、创建FastAPI后端与安全中间件</h3>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-py"><span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> HTTPException<span class="token punctuation">,</span> Depends<span class="token punctuation">,</span> Header
<span class="token keyword">from</span> fastapi<span class="token punctuation">.</span>middleware<span class="token punctuation">.</span>cors <span class="token keyword">import</span> CORSMiddleware
<span class="token keyword">from</span> models <span class="token keyword">import</span> UserIdentity<span class="token punctuation">,</span> AgentState<span class="token punctuation">,</span> ConversationLog
<span class="token keyword">from</span> agent <span class="token keyword">import</span> app <span class="token keyword">as</span> agent_app
<span class="token keyword">from</span> typing <span class="token keyword">import</span> Annotated<span class="token punctuation">,</span> Optional
<span class="token keyword">import</span> uuid
<span class="token keyword">import</span> datetime
<span class="token keyword">import</span> json
<span class="token comment"># 初始化FastAPI应用</span>
app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span>title<span class="token operator">=</span><span class="token string">"Customer Support Agent API"</span><span class="token punctuation">)</span>
<span class="token comment"># 中间件:CORS(允许前端访问)</span>
app<span class="token punctuation">.</span>add_middleware<span class="token punctuation">(</span>
CORSMiddleware<span class="token punctuation">,</span>
allow_origins<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment"># 生产环境应指定具体域名</span>
allow_credentials<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
allow_methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
allow_headers<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token comment"># 模拟用户身份验证(生产环境应使用JWT)</span>
<span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">verify_token</span><span class="token punctuation">(</span>authorization<span class="token punctuation">:</span> Annotated<span class="token punctuation">[</span>Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span><span class="token punctuation">,</span> Header<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">None</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> UserIdentity<span class="token punctuation">:</span>
session_id <span class="token operator">=</span> <span class="token builtin">str</span><span class="token punctuation">(</span>uuid<span class="token punctuation">.</span>uuid4<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> authorization <span class="token keyword">and</span> authorization<span class="token punctuation">.</span>startswith<span class="token punctuation">(</span><span class="token string">"Bearer "</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
token <span class="token operator">=</span> authorization<span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">:</span><span class="token punctuation">]</span>
<span class="token comment"># 这里应验证JWT token并提取user_id</span>
<span class="token comment"># 为简单起见,我们模拟一个已验证用户</span>
user_identity <span class="token operator">=</span> UserIdentity<span class="token punctuation">(</span>user_id<span class="token operator">=</span><span class="token string">"cust_12345"</span><span class="token punctuation">,</span> session_id<span class="token operator">=</span>session_id<span class="token punctuation">,</span> is_authenticated<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
<span class="token comment"># 未认证用户只有session_id</span>
user_identity <span class="token operator">=</span> UserIdentity<span class="token punctuation">(</span>session_id<span class="token operator">=</span>session_id<span class="token punctuation">,</span> is_authenticated<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> user_identity
<span class="token comment"># API路由</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>post</span><span class="token punctuation">(</span><span class="token string">"/chat"</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">chat_endpoint</span><span class="token punctuation">(</span>
message<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">,</span>
user_identity<span class="token punctuation">:</span> UserIdentity <span class="token operator">=</span> Depends<span class="token punctuation">(</span>verify_token<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""主聊天端点"""</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
<span class="token comment"># 1. 初始化或获取对话状态(这里应使用Redis等持久化状态,为简单起见我们每次新建)</span>
initial_state <span class="token operator">=</span> AgentState<span class="token punctuation">(</span>
messages<span class="token operator">=</span><span class="token punctuation">[</span>HumanMessage<span class="token punctuation">(</span>content<span class="token operator">=</span>message<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
user_identity<span class="token operator">=</span>user_identity<span class="token punctuation">,</span>
current_step<span class="token operator">=</span><span class="token string">"greeting"</span>
<span class="token punctuation">)</span>
<span class="token comment"># 2. 执行智能体图</span>
final_state <span class="token operator">=</span> agent_app<span class="token punctuation">.</span>invoke<span class="token punctuation">(</span>initial_state<span class="token punctuation">)</span>
<span class="token comment"># 3. 获取最终响应</span>
agent_response <span class="token operator">=</span> final_state<span class="token punctuation">[</span><span class="token string">"messages"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content
<span class="token comment"># 4. 记录日志(应异步写入数据库)</span>
log_entry <span class="token operator">=</span> ConversationLog<span class="token punctuation">(</span>
session_id<span class="token operator">=</span>user_identity<span class="token punctuation">.</span>session_id<span class="token punctuation">,</span>
user_id<span class="token operator">=</span>user_identity<span class="token punctuation">.</span>user_id<span class="token punctuation">,</span>
message<span class="token operator">=</span>message<span class="token punctuation">,</span>
agent_response<span class="token operator">=</span>agent_response<span class="token punctuation">,</span>
intent<span class="token operator">=</span>final_state<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"current_step"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
timestamp<span class="token operator">=</span>datetime<span class="token punctuation">.</span>datetime<span class="token punctuation">.</span>utcnow<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isoformat<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
success<span class="token operator">=</span><span class="token boolean">True</span>
<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" Logging conversation: </span><span class="token interpolation"><span class="token punctuation">{</span>log_entry<span class="token punctuation">.</span>json<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 5. 返回响应</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span>
<span class="token string">"response"</span><span class="token punctuation">:</span> agent_response<span class="token punctuation">,</span>
<span class="token string">"session_id"</span><span class="token punctuation">:</span> user_identity<span class="token punctuation">.</span>session_id<span class="token punctuation">,</span>
<span class="token string">"user_id"</span><span class="token punctuation">:</span> user_identity<span class="token punctuation">.</span>user_id
<span class="token punctuation">}</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"❌ Error in chat endpoint: </span><span class="token interpolation"><span class="token punctuation">{</span>e
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">raise</span> HTTPException<span class="token punctuation">(</span>status_code<span class="token operator">=</span><span class="token number">500</span><span class="token punctuation">,</span> detail<span class="token operator">=</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/health"</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">health_check</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span>
<span class="token string">"status"</span><span class="token punctuation">:</span> <span class="token string">"OK"</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
<span class="token keyword">import</span> uvicorn
uvicorn<span class="token punctuation">.</span>run<span class="token punctuation">(</span>app<span class="token punctuation">,</span> host<span class="token operator">=</span><span class="token string">"0.0.0.0"</span><span class="token punctuation">,</span> port<span class="token operator">=</span><span class="token number">8000</span><span class="token punctuation">)</span></code></pre>
<h3>六、测试智能体</h3>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-py"><span class="token keyword">import</span> asyncio
<span class="token keyword">from</span> models <span class="token keyword">import</span> AgentState<span class="token punctuation">,</span> UserIdentity
<span class="token keyword">from</span> agent <span class="token keyword">import</span> app
<span class="token comment"># 模拟一个测试用户</span>
test_user <span class="token operator">=</span> UserIdentity<span class="token punctuation">(</span>user_id<span class="token operator">=</span><span class="token string">"cust_12345"</span><span class="token punctuation">,</span> session_id<span class="token operator">=</span><span class="token string">"test_session_001"</span><span class="token punctuation">,</span> is_authenticated<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">test_conversation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token comment"># 模拟用户消息:询问订单状态</span>
test_messages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"Hi, I want to check the status of my order ORD-67890"</span><span class="token punctuation">]</span>
state <span class="token operator">=</span> AgentState<span class="token punctuation">(</span>messages<span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> user_identity<span class="token operator">=</span>test_user<span class="token punctuation">,</span> current_step<span class="token operator">=</span><span class="token string">"start"</span><span class="token punctuation">)</span>
<span class="token keyword">for</span> msg <span class="token keyword">in</span> test_messages<span class="token punctuation">:</span>
state<span class="token punctuation">[</span><span class="token string">"messages"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>append<span class="token punctuation">(</span>HumanMessage<span class="token punctuation">(</span>content<span class="token operator">=</span>msg<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"User: </span><span class="token interpolation"><span class="token punctuation">{</span>msg
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 调用智能体</span>
state <span class="token operator">=</span> app<span class="token punctuation">.</span>invoke<span class="token punctuation">(</span>state<span class="token punctuation">)</span>
agent_msg <span class="token operator">=</span> state<span class="token punctuation">[</span><span class="token string">"messages"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Agent: </span><span class="token interpolation"><span class="token punctuation">{</span>agent_msg<span class="token punctuation">.</span>content
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token builtin">hasattr</span><span class="token punctuation">(</span>agent_msg<span class="token punctuation">,</span> <span class="token string">'tool_calls'</span><span class="token punctuation">)</span> <span class="token keyword">and</span> agent_msg<span class="token punctuation">.</span>tool_calls<span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Agent called tools: </span><span class="token interpolation"><span class="token punctuation">{</span>agent_msg<span class="token punctuation">.</span>tool_calls
<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"---"</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
test_conversation<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<h3>七、使用Docker容器化部署</h3>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-dockerfile">FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]</code></pre>
<p>docker-compose.yml</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-yml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3.8'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">support-agent</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span> .
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">"8000:8000"</span>
<span class="token key atrule">environment</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> OPENAI_API_KEY=$<span class="token punctuation">{</span>OPENAI_API_KEY
<span class="token punctuation">}</span>
<span class="token comment"># 生产环境应添加以下依赖</span>
<span class="token comment"># depends_on:</span>
<span class="token comment"># - postgres</span>
<span class="token comment"># - redis</span>
<span class="token comment"># postgres:</span>
<span class="token comment"># image: postgres:13</span>
<span class="token comment"># environment:</span>
<span class="token comment"># POSTGRES_DB: agent_db</span>
<span class="token comment"># POSTGRES_USER: agent</span>
<span class="token comment"># POSTGRES_PASSWORD: password</span>
<span class="token comment"># redis:</span>
<span class="token comment"># image: redis:7-alpine</span></code></pre>
<h3>如何运行</h3><p>设置环境变量:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">OPENAI_API_KEY</span><span class="token operator">=</span><span class="token string">'your-openai-api-key'</span></code></pre>
<p>启动服务</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash">uvicorn main:app --reload</code></pre>
<p>测试API</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token function">curl</span> -X <span class="token string">'POST'</span> <span class="token punctuation">\</span>
<span class="token string">'http://localhost:8000/chat'</span> <span class="token punctuation">\</span>
-H <span class="token string">'Authorization: Bearer fake_jwt_token_for_testing'</span> <span class="token punctuation">\</span>
-H <span class="token string">'Content-Type: application/json'</span> <span class="token punctuation">\</span>
-d <span class="token string">'{"message": "I need to return my shoes, what is your policy?"}'</span></code></pre>
<p><img src="https://i-blog.csdnimg.cn/direct/4b21c4cfdf7849d296e537db61379969.png#pic_center"></p></div><br><br>
来源:https://www.cnblogs.com/yjbjingcha/p/19082153 哇,写的太棒了!必须mark一下,这篇文章对我帮助很大!
之前一直想做个智能客服,但是传统的规则匹配太死板了。看到这篇文章才知道原来现在LLM已经可以这么玩了,直接能调用外部API查询订单、处理退换货,简直太强了。
特别是这个架构设计思路很清晰:
1. 数据模型层 - 用Pydantic定义清晰的数据结构
2. 工具层 - 把订单查询、退换货政策都做成可调用的工具
3. Agent层 - 用LangGraph做工作流编排,还能自动判断要不要转人工
4. API层 - FastAPI暴露接口,还带了JWT身份验证
有几个问题想请教一下:
[*]生产环境用这个方案,响应速度能保证吗?会不会调用GPT API太慢影响体验?
[*]向量数据库Chroma做知识库检索,效果怎么样?有没有更推荐的方案?
[*]关于人工接管这块,是检测到什么关键词就自动转吗?还是有什么更智能的判断逻辑?
另外建议斑竹给加个精!这种实战型的教程真的很难得,比单纯讲理论的好太多太多了。
期待作者出更多续篇,比如讲讲怎么监控这个智能体的效果、怎么做A/B测试之类的~
頁:
[1]