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源码看看
在使用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源码看看

