系列 · 阿里云百炼 · 第 7 篇

阿里云百炼(七):内置 Web Search 与 Code Interpreter

通过 Responses API 在服务端跑 web_search、web_extractor 与 code_interpreter——不用自己写工具循环的迷你 agent。

上一篇手搓了一个编码 agent:定义工具、循环、分发、重复。当工具是你自己的(你的文件系统、你的测试 runner)时,这是对的套路。但对两个极其常见的工具,联网搜索和跑一段代码,Model Studio 现在在服务端替你跑。你打开一个开关,平台在一次 API 调用里完成搜索或执行的往返,最终答案直接回给你。本文就是这些内置工具的实战指南。


拿到 Web Search 的两条路#

入口有两个,选错了能浪费一天。

简单那条,Chat Completions 上的 enable_search 如果你只想要「用当前网络信息回答这个问题」,对现有聊天代码改动最小的就是加一个参数。用 DashScope 原生 SDK:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import os, dashscope

response = dashscope.Generation.call(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    model="qwen3-max",
    messages=[{"role": "user", "content": "What will the weather be in Hangzhou tomorrow?"}],
    enable_search=True,
    result_format="message",
)
print(response.output.choices[0].message.content)

就这样。模型自己判断要不要搜,去搜,把结果揉进答案。thinking 和非 thinking 模式都支持 agentagent_max 两种搜索策略,模型可以发多次、逐步收敛的查询,而不是一锤子。对一个偶尔需要新鲜事实的聊天机器人,enable_search=True 就够了。

强大那条,带显式工具的 Responses API。 当你不只要搜,还想让模型打开页面、对找到的内容跑代码时,就转到 client.responses.create(...) 并显式传工具。本文剩下讲的都是这条路。

Responses API 与内置工具块#

Responses API 是更新、更面向 agent 的接口。请求更扁平,用 input 而非 messages,内置工具按 type 挂上去:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    # 国际站:"https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
)

response = client.responses.create(
    model="qwen3-max-2026-01-23",
    input="Find Alibaba Cloud's latest Model Studio announcement and summarize the key points.",
    tools=[
        {"type": "web_search"},
        {"type": "web_extractor"},
        {"type": "code_interpreter"},
    ],
    extra_body={"enable_thinking": True},
)
print(response.output_text)

先记住三点:

  • 三个工具是配套用的。 web_search 找 URL,web_extractor 打开它们抓全文,code_interpreter 对抓到的内容跑分析。文档明确建议复杂任务把三个都开,效果最好。
  • web_extractor 必须跟 web_search 配对,单独用它没东西可抽。
  • qwen3-max / qwen3-max-2026-01-23 用这些工具时需要 thinking mode,所以要带 enable_thinking=Trueqwen3.5-plus 则不需要。这点搞错了,工具会静默不触发。

读输出:不只是文本#

response.output_text 给你最终答案字符串,对聊天 UI 够用。但有意思的部分,模型搜了什么、跑了什么,在 response.output 里,那是一个按类型标注的数组。需要透明度或引用时就遍历它:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
for item in response.output:
    if item.type == "reasoning":
        pass  # 思考链;我记日志,不展示
    elif item.type == "web_search_call":
        print("searched:", item.action.query)
    elif item.type == "web_extractor_call":
        print("opened a page")
    elif item.type == "message":
        # 最终答案,可能带 annotations(引用)
        print(item.content)

这条按类型标注的流,就是你给用户搭「助手先搜了 X、再读了 Y、然后算了 Z」轨迹的依据,和研究类 agent 一样的 UX 模式,只是编排发生在服务端。要统计一次请求用了多少次工具调用(做成本归因),usage 块里带着:

1
2
3
usage = response.usage
if hasattr(usage, "x_tools") and usage.x_tools:
    print("web_search count:", usage.x_tools.get("web_search", {}).get("count", 0))

Code Interpreter:模型替你跑 Python#

code_interpreter 给模型一个沙箱 Python 运行时。它写代码,平台执行,模型读结果再继续。凡是 LLM 在脑子里做不好的事,这都是对的工具:精确算术、解析脏 CSV、算个统计量、出张图。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
response = client.responses.create(
    model="qwen3.5-plus",
    input=(
        "Here is monthly revenue: Jan 12000, Feb 9800, Mar 15400, Apr 11200, "
        "May 18900, Jun 16700. Compute the month-over-month growth rates and the "
        "compound monthly growth rate, and tell me which month grew fastest."
    ),
    tools=[{"type": "code_interpreter"}],
)
print(response.output_text)

这里赢在正确性。让 qwen3.5-plus 在脑子里算复合增长率,偶尔会错得很隐蔽;开着 code_interpreter 问,它就写公式、跑出来、报一个你能信的数。对数据分析类聊天功能,这就是 demo 和产品的区别。注意同样的 thinking-mode 规则:qwen3-maxenable_thinking=Trueqwen3.5-plus 不用。

何时用内置、何时自己搭#

内置工具 vs 自建 function tools
内置工具在服务端运行、零基础设施;自建 function tools 给你完全控制。按任务是否必须触达自己的系统来选。

我选内置工具,当:

  • 工具是 web search 或通用代码执行,平台做得好、否则得我自己运营(一个搜索 API key、一个沙箱)的两件事。
  • 我想要编排放在服务端,没有工具循环、不用解析 tool_calls、不用写重试逻辑。一次调用进、答案出。
  • 任务是偶发的,按内置工具调用次数付费比自己跑搜索 / 沙箱基础设施划算。

我自己搭(第六篇那套),当:

  • 工具碰我自己的系统,我的数据库、我的文件、我的内部 API。平台够不着这些。
  • 我需要对每一步精细控制,自定义重试、缓存、对每个工具输入输出做审计。
  • 量大到按次工具计价打不过自建基础设施。

一条关于成本的提醒:截至写作时,web_extractorcode_interpreter 处于限时免费期,而 web_search 按次计费(就是上面那个 usage.x_tools 计数)。别按「永久免费」做架构,从第一天就给工具调用计量,免费期结束时账单才不会吓你一跳。

一个组合示例:先研究后计算#

三个工具合在一起才出彩。「查当前美元/人民币汇率,再换算这几张发票金额」需要一次搜索、一次页面读取、一次算术,一次 Responses 调用全包:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
response = client.responses.create(
    model="qwen3-max-2026-01-23",
    input=(
        "Look up today's USD to CNY exchange rate, then convert these USD "
        "invoice totals to CNY and give me the sum: 1250.00, 880.50, 3340.75."
    ),
    tools=[{"type": "web_search"}, {"type": "web_extractor"}, {"type": "code_interpreter"}],
    extra_body={"enable_thinking": True},
)
print(response.output_text)

模型搜汇率、从财经页面抽出来,再用 code_interpreter 做乘法和求和,而且准确。手搓这套意味着一个搜索集成、一个 HTML 抓取器、外加一个计算步骤。这里就一次调用。

接下来#

这就给七篇系列收了尾:平台与计费(一)、LLM API 与 function calling(二)、多模态 Qwen-Omni(三)、Wanxiang 视频(四)、Qwen TTS(五)、编码 agent(六)、内置工具(七)。主线始终如一:百炼不断把能力从「你来编排」挪向「平台来编排」,先是 function calling,再是 agent,如今是服务端工具。平台上的下一站是完整托管 agent(Agent 2.0),它把知识库和 MCP 统一到模型自己的规划之下,当你不再满足于一次 Responses 调用时,这是顺理成章的下一步。

本系列

阿里云百炼 7 篇

  1. 01 阿里云百炼(一):平台概览与第一个请求
  2. 02 阿里云百炼(二):Qwen API 生产接入
  3. 03 阿里云百炼(三):Qwen-Omni 多模态理解
  4. 04 阿里云百炼(四):万相视频生成端到端
  5. 05 阿里云百炼(五):Qwen-TTS 语音合成
  6. 06 阿里云百炼(六):Qwen3-Coder 与编码 Agent
  7. 07 阿里云百炼(七):内置 Web Search 与 Code Interpreter 当前

读有所得?

在 GitHub 关注我 → 新文大约每周一篇

GitHub