📚 Termux 无 Root 学习开发系列
阶段一:环境搭建与终端基础 ✅ 已完成
01-05 安装 → 包管理 → 文件管理 → Vim/tmux
阶段二:编程开发环境 ✅ 已完成
06-09 Python → C/C++ → Node.js → Git
阶段三:网络与远程操作 ✅ 已完成
10-12 SSH → 网络工具 → 网络代理
阶段四:Termux:API 与自动化 ✅ 已完成
13-14 硬件调用 → 定时任务
阶段五:proot-distro 完整 Linux ✅ 已完成
15-17 proot-distro → Jupyter → 桌面环境/VNC
阶段六:AI 与 AIGC 实战
18 调用 LLM API 对话与自动化(当前篇)
19 llama.cpp 本地模型推理(待制作)
20 RAG 知识库与本地文档问答(待制作)
阶段七至九共 8 篇,后续持续更新

18 调用 LLM API 对话与自动化

难度:高级 · 阶段六:AI 与 AIGC 实战 · 约 15 分钟阅读
读完本篇你将能:

手机里的终端以前只能执行命令,现在它可以"思考"了。把大模型 API 接进 Termux,就像给你的口袋 Linux 配了一位随叫随到的技术顾问——写脚本卡住了让它补代码,看不懂报错让它解释,甚至能让它直接调用手机传感器读取数据。

本篇从最基础的 API 调用开始,逐步深入到流式输出、多轮对话、Function Calling,最后亲手搭一个终端 AI 助手。所有代码都可以在 Termux 原生 Python 环境中直接运行,不需要 proot-distro。

📖 本篇目录
01 API 选择与环境准备
02 基础调用:单轮对话
03 多轮对话与上下文管理
04 流式输出:逐字打印体验
05 Function Calling 实战
06 构建终端 AI 聊天助手
07 三个实用场景

01 API 选择与环境准备

大模型 API 服务商很多,对 Termux 开发者而言,选择标准就三条:价格低、兼容 OpenAI SDK 格式、国内访问稳定。DeepSeek API 同时满足这三点,是国内开发者的首选。

Bash
# 安装 openai SDK(兼容 DeepSeek)
pip install openai rich
# 验证版本
python -c "import openai; print(openai.__version__)"
3.3.1

截至 2026 年 8 月,OpenAI Python SDK 最新稳定版为 3.3.1。DeepSeek API 完全兼容 OpenAI SDK 的 /v1/chat/completions 接口,只需修改 base_url 和 api_key 即可。

主流 API 对比

模型 输入价 / 百万 token 上下文 特点
deepseek-v4-flash $0.14 100 万 速度快、日常对话首选
deepseek-v4-pro $0.435 100 万 推理强、Agent 能力优秀
gpt-4o-mini $0.15 128K 多模态、需科学上网
💡 小贴士:API Key 安全存放
不要把 API Key 硬编码在脚本里。用环境变量 DEEPSEEK_API_KEY 传递,在 ~/.bashrc 中 export 即可。这样即使脚本泄露,Key 也不会跟着泄露。

02 基础调用:单轮对话

先从最简单的单轮对话开始——发一条消息,拿一条回复。DeepSeek 兼容 OpenAI SDK,所以初始化客户端时只需把 base_url 指向 DeepSeek 的域名。

simple_chat.py
1
2
3
4
5
6
7
8
9
10
11
import os
from openai import OpenAI
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)
response = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[

messages 参数是一个列表,每条消息是一个字典,包含 role 和 content。role 有三种:system(系统提示词,设定 AI 行为)、user(用户输入)、assistant(AI 回复)。

续 simple_chat.py
11
12
13
14
15
16
17
18
        {"role": "system", "content": "你是一个简洁的终端助手"},
        {"role": "user", "content": "用一行命令查看磁盘使用情况"}
    ]
)
print(response.choices[0].message.content)
# 输出:df -h  # 以人类可读格式显示各分区使用情况
#      如果想看具体目录占用,用 du -sh /path
⚠️ 常见错误
api_key 写死在代码里提交到 Git
✅ 用环境变量 os.getenv("DEEPSEEK_API_KEY") 获取,在 .bashrc 中 export
忘记设置 base_url,默认调用 OpenAI 报错 401
✅ DeepSeek 必须设置 base_url="https://api.deepseek.com"

03 多轮对话与上下文管理

单轮对话只能一问一答,没有记忆。要实现真正的聊天体验,需要把历史消息全部攒在 messages 列表里,每次发新消息时把整个列表发给模型。模型根据完整上下文来生成回复。

multi_turn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
from openai import OpenAI
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)
# 维护消息历史列表
messages = [
    {"role": "system", "content": "你是一个简洁的终端助手"}
]
def chat(user_input):
    messages.append({"role": "user", "content": user_input})
    resp = client.chat.completions.create(
        model="deepseek-v4-flash",
续 multi_turn.py
17
18
19
20
21
22
23
24
25
26
27
28
        messages=messages
    )
    reply = resp.choices[0].message.content
    messages.append({"role": "assistant", "content": reply})
    return reply
# 测试多轮对话
print("用户:用Python写斐波那契")
print("AI:" + chat("用Python写斐波那契数列"))
print("用户:改成递归版")
print("AI:" + chat("改成递归版本"))
# 第二次调用时模型记得"改成递归"指的是斐波那契

多轮对话的核心就是这个 messages 列表——它是模型的"短期记忆"。每次对话都把完整历史发过去,模型才能理解上下文。但消息越攒越长,token 消耗也越来越高,实际项目中需要做上下文裁剪,比如只保留最近 20 轮对话。

💡 小贴士:控制上下文长度
当 len(messages) > 20 时,保留 system 消息和最近 19 轮对话,删除最老的 user/assistant 配对。或者用 tiktoken 库精确计算 token 数,按 token 预算裁剪。

04 流式输出:逐字打印体验

默认情况下,API 等模型生成完全部内容才一次性返回,长回复要等好几秒。开启 stream=True 后,模型每生成几个 token 就推过来,终端里就能像聊天软件一样逐字显示,体验提升很大。

stream_chat.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sys
import os
from openai import OpenAI
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)
def stream_chat(prompt):
    stream = client.chat.completions.create(
        model="deepseek-v4-flash",
        messages=[{"role": "user", "content": prompt}],
        stream=True
    )
    
    full_reply = ""
续 stream_chat.py
17
18
19
20
21
22
23
24
25
    for chunk in stream:
        delta = chunk.choices[0].delta
        if delta.content:
            full_reply += delta.content
            sys.stdout.write(delta.content)
            sys.stdout.flush()
    print()  # 最后换行
    return full_reply
stream_chat("解释一下什么是大语言模型,用三句话")

流式输出的关键是 stream=True 参数和遍历 chunk 的循环。每个 chunk 只带一点点内容(delta.content),边收边打印,用户就感觉模型在"打字"。记得用 sys.stdout.flush() 强制刷新缓冲区,否则内容会攒到一行结束才显示。

05 Function Calling 实战

Function Calling 是大模型最实用的能力之一:你告诉模型有哪些工具可用,模型判断什么时候该用工具,返回工具调用的参数,你执行工具后把结果回传给模型,模型再基于结果生成回答。整个过程模型自主决策,不需要你手动路由。

工作流程

① 用户提问
→
② 模型决定调用工具
→
③ 执行函数
→
④ 模型基于结果回答

在 Termux 环境下,Function Calling 最酷的用法是让 LLM 调用 Termux:API——等于给 AI 开了手机硬件的权限:读电池、查位置、发通知、拍照,都能用自然语言指挥。

function_calling.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import os, subprocess, json
from openai import OpenAI
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)
# 定义工具:读取手机电池状态
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_battery_status",
            "description": "获取手机电池电量和充电状态",
            "parameters": {"type": "object", "properties": {}, "required": []}
        }
    }
]
续 function_calling.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 实际执行工具的函数
def get_battery_status():
    result = subprocess.run(
        ["termux-battery-status"],
        capture_output=True, text=True
    )
    return result.stdout
# 主循环:用户提问 → 模型可能调用工具 → 执行 → 再问模型
messages = [{"role": "user", "content": "我手机还有多少电?"}]
resp = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=messages,
    tools=tools
)
msg = resp.choices[0].message
if msg.tool_calls:
续 function_calling.py
34
35
36
37
38
39
40
41
42
43
44
45
    messages.append(msg)  # 把 assistant 的 tool_call 消息加入历史
    for tool_call in msg.tool_calls:
        func_name = tool_call.function.name
        if func_name == "get_battery_status":
            result = get_battery_status()
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": result
            })
    # 把工具结果回传给模型,获取最终回答
    resp2 = client.chat.completions.create(
        model="deepseek-v4-flash", messages=messages)
    print(resp2.choices[0].message.content)

运行后你会看到类似这样的输出:"你的手机当前电量为 78%,正在通过 USB 充电。"——模型自动判断需要调用电池查询工具,执行后用自然语言把结果说给你听。这就是 Agent 的雏形。

💡 小贴士:工具描述越精确越好
function 的 description 和参数描述直接影响模型判断是否调用该工具。描述越清晰,模型越不容易误调用。参数的 enum 字段可以限定可选值,进一步减少错误。

06 构建终端 AI 聊天助手

前面学了单轮、多轮、流式输出、Function Calling,现在把这些能力整合起来,做一个真正能用的终端 AI 聊天助手。支持多会话管理、历史记录持久化、流式输出,界面用 rich 库美化。

ai_chat.py 第一部分:初始化与历史管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import os, sys, json
from pathlib import Path
from openai import OpenAI
from rich.console import Console
from rich.panel import Panel
from rich.markdown import Markdown
console = Console()
HISTORY_DIR = Path.home() / ".ai_chat_history"
HISTORY_DIR.mkdir(exist_ok=True)
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)
def save_session(session_id, messages):
    path = HISTORY_DIR / f"{session_id}.json"
    path.write_text(json.dumps(messages, ensure_ascii=False, indent=2))
def load_session(session_id):
ai_chat.py 第二部分:流式聊天函数 + 主循环
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    path = HISTORY_DIR / f"{session_id}.json"
    if path.exists():
        return json.loads(path.read_text())
    return [{"role": "system", "content": "你是一个有帮助的AI助手"}]
def stream_chat(messages):
    stream = client.chat.completions.create(
        model="deepseek-v4-flash",
        messages=messages, stream=True
    )
    full = ""
    for chunk in stream:
        delta = chunk.choices[0].delta
        if delta.content:
            full += delta.content
            yield delta.content
    messages.append({"role": "assistant", "content": full})
def list_sessions():
    return sorted(
        [p.stem for p in HISTORY_DIR.glob("*.json")],
        reverse=True
    )
ai_chat.py 第三部分:主循环交互
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
if __name__ == "__main__":
    console.print(Panel("AI 终端助手 | 输入 /help 查看命令", style="bold purple"))
    
    import datetime
    session_id = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    messages = load_session(session_id)
    
    while True:
        try:
            user_input = console.input("[bold green]你:[/bold green] ")
        except (EOFError, KeyboardInterrupt):
            console.print("\n再见!")
            break
        
        if user_input == "/quit": break
        if user_input == "/list":
            console.print("历史会话:" + ", ".join(list_sessions()))
            continue
ai_chat.py 第四部分:发送消息 + 流式输出
59
60
61
62
63
64
65
66
67
68
69
70
        
        messages.append({"role": "user", "content": user_input})
        console.print("[bold purple]AI:[/bold purple] ", end="")
        for token in stream_chat(messages):
            console.print(token, end="")
        console.print()  # 换行
        
        save_session(session_id, messages)  # 每轮对话后保存
        
# 运行方式:python ai_chat.py
# 特殊命令:/quit 退出 /list 查看历史会话
# 所有对话自动保存到 ~/.ai_chat_history/

这个聊天助手有三个核心特性:流式输出打字感、多会话历史持久化(按时间戳命名存 JSON)、rich 库美化界面。直接 python ai_chat.py 就能用。后续可以继续扩展,比如加上 Function Calling 接入 Termux:API,或者支持切换不同模型。

07 三个实用场景

学会了 API 调用和 Function Calling,具体能做什么?下面三个场景展示如何把 LLM 变成 Termux 里的生产力工具。

场景一:自然语言转命令

记不住复杂的命令参数?用自然语言描述需求,让 LLM 生成命令并自动执行。注意执行前务必确认,避免误操作。

nl2cmd.py
# 让 LLM 把自然语言翻译成 shell 命令
def nl2cmd(prompt):
    resp = client.chat.completions.create(
        model="deepseek-v4-flash",
        messages=[{
            "role": "system",
            "content": "只输出shell命令,不要解释。用户在Termux(Linux/Android)环境。"
        }, {"role": "user", "content": prompt}]
    )
    return resp.choices[0].message.content.strip()
# 用法:nl2cmd("找出当前目录下最大的5个文件")
# 输出:du -sh * | sort -rh | head -5

场景二:代码解释器

读到一段看不懂的代码?直接粘贴到终端里,让 AI 逐行解释。配合第 13 篇学的剪贴板功能,可以一键把复制的代码送去解释。

explain_code.py
def explain(code, lang="python"):
    resp = client.chat.completions.create(
        model="deepseek-v4-flash",
        messages=[
            {"role": "system", "content": "逐行解释代码,先给整体功能,再逐行注释"},
            {"role": "user", "content": code}
    ], stream=True
    )
    for chunk in stream:
        if chunk.choices[0].delta.content:
            sys.stdout.write(chunk.choices[0].delta.content)
            sys.stdout.flush()

场景三:语音日记助手

结合 Termux:API 的录音功能和 LLM 的文本整理能力,做一个语音日记:对着手机说话,自动转文字 → LLM 润色整理 → 保存成 Markdown 日记文件。

💡 小贴士:语音转文字方案
Termux 原生没有自带的语音识别,可以用三种方案:1)调用 OpenAI Whisper API;2)在 proot Ubuntu 中安装 whisper.cpp 本地识别;3)用 termux-microphone-record 录音后上传到第三方语音识别 API。推荐方案 2,离线运行不花钱,下一篇 llama.cpp 会详细讲解本地模型推理。
✏️ 分级练习
🟢 基础验证 单轮 API 调用
编写一个 Python 脚本,调用 deepseek-v4-flash 模型,输入"用一句话解释什么是 API",打印模型回复。确保脚本能在 Termux 中直接运行。
💡 参考解法:使用 openai SDK 初始化 client,设置 base_url 和 api_key,调用 chat.completions.create(),从 choices[0].message.content 获取回复。
🟡 组合应用 流式多轮对话
基于本章的 stream_chat 函数,实现一个交互式多轮对话程序:用户输入一行,AI 流式回复一行,输入 /exit 退出。要求:1)支持流式输出逐字打印;2)维护对话历史;3)退出时显示本轮总 token 消耗(可从 usage 字段获取,非流式才有 usage)。
💡 参考解法:用 while True 循环 + input() 读取用户输入,维护 messages 列表,stream=True 流式输出,/exit 时 break。token 统计可以在最后一轮改为非流式调用来获取 usage。
🔴 开放挑战 Termux:API + Function Calling
实现一个"手机管家"AI 助手:至少集成 3 个 Termux:API 工具(如电池状态、通知、位置、手电筒),通过 Function Calling 让用户用自然语言控制手机。例如:"还有多少电?"→读电池,"帮我设个 10 分钟后的提醒"→发通知。思考:如何设计工具描述让模型正确选择?如何处理工具调用失败的情况?
提示:先定义 tools 列表描述每个 API 的功能和参数,主循环中检测 tool_calls 并执行对应 subprocess 调用,将结果以 role=tool 的消息回传后再次请求模型。
🏷️ 知识回顾
DeepSeek API OpenAI SDK base_url 配置 单轮对话 多轮上下文 流式输出 stream Function Calling rich 终端美化 历史记录持久化 环境变量存 Key
📬 下一篇预告
第 19 篇:llama.cpp 本地模型推理——API 虽好但要联网还要花钱,llama.cpp 让你在手机上本地运行大语言模型,完全离线、零成本。从编译安装到 GGUF 模型下载,从命令行交互到本地 API 服务,让你的手机变身离线 AI 助理。
关注系列,持续更新中 · 点赞在看支持作者