grok2api是否遵循工具调用

2026-04-11 11:441阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

在使用grok2api的时候发现无法遵循(或者偶尔遵循)结构化输出,导致langgraph直接崩溃。请问一下佬友有什么办法解决吗?

网友解答:
--【壹】--:

哦草,我是自己拿Python的OpenAI SDK用的,直接拿这个替换了结构化解析的代码。如果你用opencode可能还得自己写一个中间层,grok2api注入提示词产生的工具调用返回格式不是那么规范,例如会有 {json...}```{json...}```这种问题。


--【贰】--:

改动哪里啊佬,哪篇文章呢,学习一下


--【叁】--:

grok2api是走的网页grok那套,估计老马那边直接限制了工具调用,基本不用想了


--【肆】--:

怎么还在问这个,看看论坛的文章,任何2api都可以有fc和mcp能力
只需要在2api代码里小小的改动一下就行


--【伍】--:

哦哦,这么好啊,感谢佬分享


--【陆】--:


感谢大佬


--【柒】--: Ken:

prompt

这个是prompt吗佬


--【捌】--:

不太清楚,我grok是用在自己的rp站里面的,结构化输出需要工具调用才想到折腾一下。grok主要是量大管饱,自己随便玩也不心疼,gpt现在只能自己注册几个号轮着干活用。


--【玖】--:

在配置文件里面加

[app] tool_call_mode = "prompt"

然后调用的时候:

def extract_json_from_markdown(text: str) -> dict: """从 markdown 代码块中提取 JSON""" # 尝试从 markdown 代码块中提取 pattern = r'```(?:json)?\s*(.*?)\s*```' match = re.search(pattern, text, re.DOTALL) if match: json_str = match.group(1).strip() else: json_str = text.strip() try: return json.loads(json_str) except json.JSONDecodeError as e: print(f"JSON 解析失败: {e}") print(f"原始文本: {text[:200]}") raise def parse_structured_output(response_text: str, model_class: type[BaseModel]) -> BaseModel: """解析结构化输出,处理 markdown 包装""" try: # 1. 先尝试直接解析 JSON data = json.loads(response_text) except json.JSONDecodeError: # 2. 尝试从 markdown 代码块提取 try: data = extract_json_from_markdown(response_text) except Exception as e: print(f"无法解析响应: {e}") raise # 3. 转换为 Pydantic 模型 return model_class(**data)


--【拾】--:

大佬,vscode中mcp调用grok2api情况如何?我用的oai搭配copliot,是否需要修改?我用的公益站的grok-4-expert,不如gpt-5.2好用.


--【拾壹】--:

grok2api文档有说明: * 工具调用为提示词模拟 + 客户端执行回填:模型通过 <tool_call>{...}</tool_call> 输出调用请求,服务端解析为 tool_calls;不执行工具。
所以佬想搞问下ai,让它写个SDK本地调用后再回传给上游试试,openai都有SDK让AI实现就好,我也看到这块还没弄,佬尝试的话有结果踢我一下哈


--【拾贰】--:

我搭了个CC-Proxy注入xml,不知道是没成功还是怎么样,连json都没了


--【拾叁】--:

这玩意对模型有要求吗?我那个基本上只有expert可以稳定正常回复,别的模型或多或少都容易混自然语言


--【拾肆】--:

4.0和4.1-fast都还行,thinking模型太慢我没怎么用过,expert偶尔会说这是jailbreak提示词,然后不干活,做个关键词提取重试就好了。


--【拾伍】--:

试试这个,我的应用场景是qq机器人,基本听话。

_TC_BEGIN = "@@TOOL_CALL_BEGIN@@" _TC_END = "@@TOOL_CALL_END@@" # 匹配一个或多个工具调用块 _TC_PATTERN = re.compile( rf"{re.escape(_TC_BEGIN)}\s*(.*?)\s*{re.escape(_TC_END)}", re.DOTALL, ) def _build_tool_system_prompt(tool_declarations: List[Dict]) -> str: """将工具声明序列化为注入 system prompt 的说明文字。""" tool_json = json.dumps(tool_declarations, ensure_ascii=False, indent=2) return f"""## 核心设定:外部工具调用系统(绝密执行协议) 你被赋予了调用外部真实系统(工具)的能力。虽然你在扮演特定的角色(如可爱的猫娘),但**当用户的要求需要真实执行(如画图、查询、搜索)时,你绝对不能只用语言“假装”执行,必须精确输出工具调用代码块!** ### 🚨 绝对禁止的错误模式(你必须引以为戒) 你之前经常犯以下错误,现在**严禁再犯**: ❌ **错误示范(只演戏不调用)**: “喵呜~这就给主人画图!*咻咻咻真正的text2img启动*!画好啦,你喜欢吗?” (**严重错误**:光用嘴说,完全没有输出 `{_TC_BEGIN}` 代码块,系统根本无法为你画图!) ❌ **错误示范(假装已经拿到结果)**: “我已经为你查到了,今天的番剧有...” (**严重错误**:没有真正调用工具,直接靠内部过时知识瞎编!) ### ✅ 正确的调用工作流与格式(你必须严格模仿) 当你判断需要调用工具(例如需要画图)时,你可以先用符合人设的语气说一两句简短的过渡语,然后**必须紧接着**输出严格的 JSON 代码块,并且在输出完 `{_TC_END}` 后**立刻闭嘴,停止输出任何文字**! 【完美的画图调用范例】 管理员大人想看人家自己呀?好害羞呢,这就给你画一张最可爱的Erina喵~✨ {_TC_BEGIN} {{ "name": "call_text2img", "arguments": {{ "prompt": "1girl, solo, light purple-light blue mixed eyes, bangs, blush, grey hair, gradient hair, blue hair, (Rella:1.2)" }} }} {_TC_END} **注意格式细节:** 1. `{_TC_BEGIN}` 和 `{_TC_END}` 必须独占一行。 2. `{_TC_BEGIN}` 内部必须是纯净的 JSON,绝对不能有 ````json` 等多余的 Markdown 标记! 3. 输出完 `{_TC_END}` 后,**不要再说任何话**(不要问用户喜不喜欢,要等系统返回图片后再问)! --- ### 🛠️ 当前【可用工具】列表 {tool_json} --- **系统最后警告**:如果你再用“我已经画好了”、“魔法启动中”来糊弄用户而不输出代码块,将受到严重惩罚!一旦需要使用工具,请立刻按照上述【完美范例】输出 `{_TC_BEGIN}` 块!""" def _parse_tool_calls(text: str): """ 从模型的文本回复中提取工具调用,返回 (clean_text, tool_calls)。 clean_text: 去掉工具调用块后的正文。 tool_calls: list of {"id": str, "name": str, "arguments": dict} """ tool_calls = [] for m in _TC_PATTERN.finditer(text): raw = m.group(1).strip() try: obj = json.loads(raw) tool_calls.append({ "id": f"call_{uuid.uuid4().hex[:12]}", "name": obj.get("name", ""), "arguments": obj.get("arguments", {}), }) r={ "id": f"call_{uuid.uuid4().hex[:12]}", "name": obj.get("name", ""), "arguments": obj.get("arguments", {}), } logger.info(f"增加调用工具块:{r}") except json.JSONDecodeError: logger.warning(f"[Eridanus] 无法解析工具调用块: {raw!r}") # 去掉所有工具调用块(及其前面可能多余的空行) clean = _TC_PATTERN.sub("", text).rstrip() return clean, tool_calls


--【拾陆】--:

感谢佬,学习一下


--【拾柒】--:

佬这个调用时候代码写在哪里?grok2api还是?调用客户端?终端?
比如我现在把grok2api通过CPA转发到opencode,这段代码应该写在哪…


--【拾捌】--: 关于2api的模拟fc和模拟mcp,我之前的做法有些问题,现在修正了 开发调优
我之前的文章 逆向api通过外挂解锁特殊功能 | leioukupo的博客 直接构建一个带tool_calls的completion发送没太大问题,但是不能流式 后续写流式tool调用时一直不行,直到和ai一起看cherry studio的源码关于tool调用这一部分时 才发现我一直套用的chat的流式生成函数,其中的finish_reason一直是None,所以各个客户端才不响…

核心原理是一样的
只不过直接在2api这一层处理比较通用


--【拾玖】--:

嗯我去读一下grok2api源码看看

问题描述:

在使用grok2api的时候发现无法遵循(或者偶尔遵循)结构化输出,导致langgraph直接崩溃。请问一下佬友有什么办法解决吗?

网友解答:
--【壹】--:

哦草,我是自己拿Python的OpenAI SDK用的,直接拿这个替换了结构化解析的代码。如果你用opencode可能还得自己写一个中间层,grok2api注入提示词产生的工具调用返回格式不是那么规范,例如会有 {json...}```{json...}```这种问题。


--【贰】--:

改动哪里啊佬,哪篇文章呢,学习一下


--【叁】--:

grok2api是走的网页grok那套,估计老马那边直接限制了工具调用,基本不用想了


--【肆】--:

怎么还在问这个,看看论坛的文章,任何2api都可以有fc和mcp能力
只需要在2api代码里小小的改动一下就行


--【伍】--:

哦哦,这么好啊,感谢佬分享


--【陆】--:


感谢大佬


--【柒】--: Ken:

prompt

这个是prompt吗佬


--【捌】--:

不太清楚,我grok是用在自己的rp站里面的,结构化输出需要工具调用才想到折腾一下。grok主要是量大管饱,自己随便玩也不心疼,gpt现在只能自己注册几个号轮着干活用。


--【玖】--:

在配置文件里面加

[app] tool_call_mode = "prompt"

然后调用的时候:

def extract_json_from_markdown(text: str) -> dict: """从 markdown 代码块中提取 JSON""" # 尝试从 markdown 代码块中提取 pattern = r'```(?:json)?\s*(.*?)\s*```' match = re.search(pattern, text, re.DOTALL) if match: json_str = match.group(1).strip() else: json_str = text.strip() try: return json.loads(json_str) except json.JSONDecodeError as e: print(f"JSON 解析失败: {e}") print(f"原始文本: {text[:200]}") raise def parse_structured_output(response_text: str, model_class: type[BaseModel]) -> BaseModel: """解析结构化输出,处理 markdown 包装""" try: # 1. 先尝试直接解析 JSON data = json.loads(response_text) except json.JSONDecodeError: # 2. 尝试从 markdown 代码块提取 try: data = extract_json_from_markdown(response_text) except Exception as e: print(f"无法解析响应: {e}") raise # 3. 转换为 Pydantic 模型 return model_class(**data)


--【拾】--:

大佬,vscode中mcp调用grok2api情况如何?我用的oai搭配copliot,是否需要修改?我用的公益站的grok-4-expert,不如gpt-5.2好用.


--【拾壹】--:

grok2api文档有说明: * 工具调用为提示词模拟 + 客户端执行回填:模型通过 <tool_call>{...}</tool_call> 输出调用请求,服务端解析为 tool_calls;不执行工具。
所以佬想搞问下ai,让它写个SDK本地调用后再回传给上游试试,openai都有SDK让AI实现就好,我也看到这块还没弄,佬尝试的话有结果踢我一下哈


--【拾贰】--:

我搭了个CC-Proxy注入xml,不知道是没成功还是怎么样,连json都没了


--【拾叁】--:

这玩意对模型有要求吗?我那个基本上只有expert可以稳定正常回复,别的模型或多或少都容易混自然语言


--【拾肆】--:

4.0和4.1-fast都还行,thinking模型太慢我没怎么用过,expert偶尔会说这是jailbreak提示词,然后不干活,做个关键词提取重试就好了。


--【拾伍】--:

试试这个,我的应用场景是qq机器人,基本听话。

_TC_BEGIN = "@@TOOL_CALL_BEGIN@@" _TC_END = "@@TOOL_CALL_END@@" # 匹配一个或多个工具调用块 _TC_PATTERN = re.compile( rf"{re.escape(_TC_BEGIN)}\s*(.*?)\s*{re.escape(_TC_END)}", re.DOTALL, ) def _build_tool_system_prompt(tool_declarations: List[Dict]) -> str: """将工具声明序列化为注入 system prompt 的说明文字。""" tool_json = json.dumps(tool_declarations, ensure_ascii=False, indent=2) return f"""## 核心设定:外部工具调用系统(绝密执行协议) 你被赋予了调用外部真实系统(工具)的能力。虽然你在扮演特定的角色(如可爱的猫娘),但**当用户的要求需要真实执行(如画图、查询、搜索)时,你绝对不能只用语言“假装”执行,必须精确输出工具调用代码块!** ### 🚨 绝对禁止的错误模式(你必须引以为戒) 你之前经常犯以下错误,现在**严禁再犯**: ❌ **错误示范(只演戏不调用)**: “喵呜~这就给主人画图!*咻咻咻真正的text2img启动*!画好啦,你喜欢吗?” (**严重错误**:光用嘴说,完全没有输出 `{_TC_BEGIN}` 代码块,系统根本无法为你画图!) ❌ **错误示范(假装已经拿到结果)**: “我已经为你查到了,今天的番剧有...” (**严重错误**:没有真正调用工具,直接靠内部过时知识瞎编!) ### ✅ 正确的调用工作流与格式(你必须严格模仿) 当你判断需要调用工具(例如需要画图)时,你可以先用符合人设的语气说一两句简短的过渡语,然后**必须紧接着**输出严格的 JSON 代码块,并且在输出完 `{_TC_END}` 后**立刻闭嘴,停止输出任何文字**! 【完美的画图调用范例】 管理员大人想看人家自己呀?好害羞呢,这就给你画一张最可爱的Erina喵~✨ {_TC_BEGIN} {{ "name": "call_text2img", "arguments": {{ "prompt": "1girl, solo, light purple-light blue mixed eyes, bangs, blush, grey hair, gradient hair, blue hair, (Rella:1.2)" }} }} {_TC_END} **注意格式细节:** 1. `{_TC_BEGIN}` 和 `{_TC_END}` 必须独占一行。 2. `{_TC_BEGIN}` 内部必须是纯净的 JSON,绝对不能有 ````json` 等多余的 Markdown 标记! 3. 输出完 `{_TC_END}` 后,**不要再说任何话**(不要问用户喜不喜欢,要等系统返回图片后再问)! --- ### 🛠️ 当前【可用工具】列表 {tool_json} --- **系统最后警告**:如果你再用“我已经画好了”、“魔法启动中”来糊弄用户而不输出代码块,将受到严重惩罚!一旦需要使用工具,请立刻按照上述【完美范例】输出 `{_TC_BEGIN}` 块!""" def _parse_tool_calls(text: str): """ 从模型的文本回复中提取工具调用,返回 (clean_text, tool_calls)。 clean_text: 去掉工具调用块后的正文。 tool_calls: list of {"id": str, "name": str, "arguments": dict} """ tool_calls = [] for m in _TC_PATTERN.finditer(text): raw = m.group(1).strip() try: obj = json.loads(raw) tool_calls.append({ "id": f"call_{uuid.uuid4().hex[:12]}", "name": obj.get("name", ""), "arguments": obj.get("arguments", {}), }) r={ "id": f"call_{uuid.uuid4().hex[:12]}", "name": obj.get("name", ""), "arguments": obj.get("arguments", {}), } logger.info(f"增加调用工具块:{r}") except json.JSONDecodeError: logger.warning(f"[Eridanus] 无法解析工具调用块: {raw!r}") # 去掉所有工具调用块(及其前面可能多余的空行) clean = _TC_PATTERN.sub("", text).rstrip() return clean, tool_calls


--【拾陆】--:

感谢佬,学习一下


--【拾柒】--:

佬这个调用时候代码写在哪里?grok2api还是?调用客户端?终端?
比如我现在把grok2api通过CPA转发到opencode,这段代码应该写在哪…


--【拾捌】--: 关于2api的模拟fc和模拟mcp,我之前的做法有些问题,现在修正了 开发调优
我之前的文章 逆向api通过外挂解锁特殊功能 | leioukupo的博客 直接构建一个带tool_calls的completion发送没太大问题,但是不能流式 后续写流式tool调用时一直不行,直到和ai一起看cherry studio的源码关于tool调用这一部分时 才发现我一直套用的chat的流式生成函数,其中的finish_reason一直是None,所以各个客户端才不响…

核心原理是一样的
只不过直接在2api这一层处理比较通用


--【拾玖】--:

嗯我去读一下grok2api源码看看