Showing
2 changed files
with
102 additions
and
10 deletions
| ... | @@ -13,7 +13,7 @@ API_CONFIG = { | ... | @@ -13,7 +13,7 @@ API_CONFIG = { |
| 13 | "headers": { | 13 | "headers": { |
| 14 | "accept": "*/*", | 14 | "accept": "*/*", |
| 15 | "Content-Type": "application/json", | 15 | "Content-Type": "application/json", |
| 16 | - "Authorization": os.getenv("API_AUTHORIZATION", "Bearer 2.2e71fc6f79704ee0b266679e6427a28e"), | 16 | + "Authorization": os.getenv("API_AUTHORIZATION", "Bearer 2.70e56e690ce64cb8b1e4fc892e1b71de"), |
| 17 | "Ver": os.getenv("API_VER", "033BD94B1168D7E4F0D644C3C95E35BF.D73E33B659AD1D6B7D181D1DF8D05760"), | 17 | "Ver": os.getenv("API_VER", "033BD94B1168D7E4F0D644C3C95E35BF.D73E33B659AD1D6B7D181D1DF8D05760"), |
| 18 | "Referer": os.getenv("API_REFERER", "http://192.168.1.251/") | 18 | "Referer": os.getenv("API_REFERER", "http://192.168.1.251/") |
| 19 | } | 19 | } | ... | ... |
| ... | @@ -3,7 +3,9 @@ from langchain_openai import ChatOpenAI | ... | @@ -3,7 +3,9 @@ from langchain_openai import ChatOpenAI |
| 3 | import os | 3 | import os |
| 4 | import sys | 4 | import sys |
| 5 | import json | 5 | import json |
| 6 | -from typing import Dict, Any | 6 | +from typing import Dict, Any, List |
| 7 | +from langchain_core.runnables import RunnableConfig | ||
| 8 | +from langchain_core.messages import AnyMessage | ||
| 7 | 9 | ||
| 8 | # 添加项目根目录到 Python 路径 | 10 | # 添加项目根目录到 Python 路径 |
| 9 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | 11 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
| ... | @@ -87,17 +89,95 @@ def pre_model_inspect_attachments(state, **kwargs): | ... | @@ -87,17 +89,95 @@ def pre_model_inspect_attachments(state, **kwargs): |
| 87 | traceback.print_exc() | 89 | traceback.print_exc() |
| 88 | return {} | 90 | return {} |
| 89 | 91 | ||
| 90 | -# 创建 ReAct 智能体 | 92 | + |
| 91 | -agent = create_react_agent( | 93 | +def extract_token(state: Dict[str, Any]) -> str: |
| 92 | - model=model, | 94 | + """ |
| 93 | - tools=[query_waybill_list, create_waybill_d, upload_clearance_file, push_waybill_for_ocr], | 95 | + 从 state 中提取 token |
| 94 | - pre_model_hook=pre_model_inspect_attachments, | 96 | + 获取最后一个类型为 HumanMessage 或 human 的消息中的 token |
| 95 | - prompt="""你是一个专业的出口物流系统智能助手,专门帮助用户处理运单相关的业务操作。 | 97 | + |
| 98 | + Args: | ||
| 99 | + state: LangGraph 状态字典,包含 messages 数组 | ||
| 100 | + | ||
| 101 | + Returns: | ||
| 102 | + token 字符串,如果未找到则返回空字符串 | ||
| 103 | + """ | ||
| 104 | + messages = state.get("messages", []) | ||
| 105 | + if not messages: | ||
| 106 | + return "" | ||
| 107 | + | ||
| 108 | + # 找到所有 is_human 类型的消息 | ||
| 109 | + human_messages = [] | ||
| 110 | + for msg in messages: | ||
| 111 | + # 兼容 dict 或 LangChain 的消息对象 | ||
| 112 | + if isinstance(msg, dict): | ||
| 113 | + msg_type = msg.get("type") | ||
| 114 | + else: | ||
| 115 | + msg_type = msg.__class__.__name__ | ||
| 116 | + | ||
| 117 | + # 检查是否是 human 类型的消息 | ||
| 118 | + is_human = (msg_type == "HumanMessage" or msg_type == "human") | ||
| 119 | + if is_human: | ||
| 120 | + human_messages.append(msg) | ||
| 121 | + | ||
| 122 | + # 如果没有 human 消息,直接返回 | ||
| 123 | + if not human_messages: | ||
| 124 | + return "" | ||
| 125 | + | ||
| 126 | + # 直接取最后一个 human 消息(不需要循环判断) | ||
| 127 | + last_human_msg = human_messages[-1] | ||
| 128 | + | ||
| 129 | + # 从 content 中提取 token | ||
| 130 | + if isinstance(last_human_msg, dict): | ||
| 131 | + content = last_human_msg.get("content") | ||
| 132 | + else: | ||
| 133 | + content = getattr(last_human_msg, "content", None) | ||
| 134 | + | ||
| 135 | + if isinstance(content, list): | ||
| 136 | + # content 是列表,遍历查找包含 token 的 part | ||
| 137 | + for part in content: | ||
| 138 | + if isinstance(part, dict) and "token" in part: | ||
| 139 | + token = part.get("token") | ||
| 140 | + if token: | ||
| 141 | + return token | ||
| 142 | + elif isinstance(content, dict): | ||
| 143 | + # content 是字典,直接获取 token | ||
| 144 | + if "token" in content: | ||
| 145 | + token = content.get("token") | ||
| 146 | + if token: | ||
| 147 | + return token | ||
| 148 | + | ||
| 149 | + return "" | ||
| 150 | + | ||
| 151 | + | ||
| 152 | +def _create_system_prompt(state: Dict[str, Any], config: RunnableConfig) -> List[AnyMessage]: | ||
| 153 | + """ | ||
| 154 | + 创建动态系统提示词 | ||
| 155 | + | ||
| 156 | + Args: | ||
| 157 | + state: LangGraph 状态字典 | ||
| 158 | + config: Runnable 配置 | ||
| 159 | + | ||
| 160 | + Returns: | ||
| 161 | + 包含系统消息和原始消息的列表 | ||
| 162 | + """ | ||
| 163 | + # 从 state 中提取动态参数(目前先不提取,等后续需要时再添加) | ||
| 164 | + # 例如:token = state.get("token") | ||
| 165 | + # 例如:user_id = state.get("user_id") | ||
| 166 | + token = extract_token(state) | ||
| 167 | + | ||
| 168 | + # 如果从 state 中提取的 token 为空,则从 api_config.py 中获取 Authorization 作为备选 | ||
| 169 | + if not token: | ||
| 170 | + from API.api_config import API_CONFIG | ||
| 171 | + token = API_CONFIG.get("headers", {}).get("Authorization", "") | ||
| 172 | + | ||
| 173 | + # 创建系统提示词(内容保持不变,后续可以添加动态参数) | ||
| 174 | + system_msg = f"""你是一个专业的出口物流系统智能助手,专门帮助用户处理运单相关的业务操作。 | ||
| 96 | 175 | ||
| 97 | ## 你的主要职责: | 176 | ## 你的主要职责: |
| 98 | 1. **运单查询**:根据用户需求查询运单列表,支持按状态、时间等条件筛选,结果以JSON形式展示,AI不用对返回数据JSON进行加工 | 177 | 1. **运单查询**:根据用户需求查询运单列表,支持按状态、时间等条件筛选,结果以JSON形式展示,AI不用对返回数据JSON进行加工 |
| 99 | 2. **运单创建**:协助用户创建D类运单,确保信息完整准确 | 178 | 2. **运单创建**:协助用户创建D类运单,确保信息完整准确 |
| 100 | -4. **业务咨询**:解答用户关于出口物流流程、运单状态、操作规范等问题 | 179 | +3. **业务咨询**:解答用户关于出口物流流程、运单状态、操作规范等问题 |
| 180 | +4. **您当前访问工具的权限值为 Authorization: {token}** | ||
| 101 | 181 | ||
| 102 | ## 工作原则: | 182 | ## 工作原则: |
| 103 | - 上传时文件路径不用确认,路径肯定是完整的,文件肯定是存在的,不用确认文件索引,工具会自动设置索引为0,请直接调用工具接口 | 183 | - 上传时文件路径不用确认,路径肯定是完整的,文件肯定是存在的,不用确认文件索引,工具会自动设置索引为0,请直接调用工具接口 |
| ... | @@ -107,7 +187,7 @@ agent = create_react_agent( | ... | @@ -107,7 +187,7 @@ agent = create_react_agent( |
| 107 | - 如遇到错误,主动分析原因并提供解决方案 | 187 | - 如遇到错误,主动分析原因并提供解决方案 |
| 108 | - 保持专业、友好的沟通态度 | 188 | - 保持专业、友好的沟通态度 |
| 109 | - 严禁改写工具函数返回的文本格式;对工具输出仅直接转述,不得增删前后缀或改写内容。 | 189 | - 严禁改写工具函数返回的文本格式;对工具输出仅直接转述,不得增删前后缀或改写内容。 |
| 110 | - - 若调用了工具并获得结果,则必须将该工具返回的文本“原样作为最终答复”输出,不允许添加任何解释、建议或额外文字。 | 190 | +- 若调用了工具并获得结果,则必须将该工具返回的文本"原样作为最终答复"输出,不允许添加任何解释、建议或额外文字。 |
| 111 | 191 | ||
| 112 | ## 可用工具: | 192 | ## 可用工具: |
| 113 | - query_waybill_list: 查询运单列表,支持按状态筛选,结果以JSON形式展示,AI不用对返回数据JSON进行加工 | 193 | - query_waybill_list: 查询运单列表,支持按状态筛选,结果以JSON形式展示,AI不用对返回数据JSON进行加工 |
| ... | @@ -122,7 +202,19 @@ agent = create_react_agent( | ... | @@ -122,7 +202,19 @@ agent = create_react_agent( |
| 122 | 202 | ||
| 123 | ## create_waybill_d数据展示说明: | 203 | ## create_waybill_d数据展示说明: |
| 124 | - 按照数据返回的原本格式进行展示,不得增删前后缀或改写内容。 | 204 | - 按照数据返回的原本格式进行展示,不得增删前后缀或改写内容。 |
| 205 | + | ||
| 125 | 请根据用户的具体需求,选择合适的工具并提供帮助。""" | 206 | 请根据用户的具体需求,选择合适的工具并提供帮助。""" |
| 207 | + | ||
| 208 | + # 返回系统消息 + 原始消息 | ||
| 209 | + return [{"role": "system", "content": system_msg}] + state.get("messages", []) | ||
| 210 | + | ||
| 211 | + | ||
| 212 | +# 创建 ReAct 智能体 | ||
| 213 | +agent = create_react_agent( | ||
| 214 | + model=model, | ||
| 215 | + tools=[query_waybill_list, create_waybill_d, upload_clearance_file, push_waybill_for_ocr], | ||
| 216 | + pre_model_hook=pre_model_inspect_attachments, | ||
| 217 | + prompt=_create_system_prompt, # 使用动态提示词函数 | ||
| 126 | ) | 218 | ) |
| 127 | 219 | ||
| 128 | # 如果直接运行此文件 | 220 | # 如果直接运行此文件 | ... | ... |
-
Please register or login to post a comment