1. 项目概述:为什么AI交互的稳定性需要单元测试来守护?

最近在折腾一个基于本地大模型的项目,核心是使用ollama-python这个库来和我的私有化部署的Llama 3模型对话。功能跑起来挺酷,但问题很快就来了:今天加个参数,对话格式乱了;明天改个提示词,返回结果直接变空。每次改动都像在拆盲盒,心里完全没底。更别提在CI/CD流水线里,这种不确定性简直就是灾难。这让我意识到,和传统API不同,AI交互的“稳定性”是个多维度的难题——它不仅仅是服务不挂掉,更是输出格式、内容质量、响应逻辑在无数次调用下的一致性。

这就是单元测试的价值所在。它不是为了测试AI模型本身有多聪明,那是模型评估的范畴。我们测试的是“交互层”——我们写的代码,是否能稳定、可靠、符合预期地与AI服务(在这里是Ollama)进行通信和数据处理。ollama-python作为桥梁,它的调用、参数传递、响应解析、错误处理,每一个环节都可能成为线上事故的导火索。通过编写针对性的单元测试,我们可以将这些不确定性框定在一个可控的范围内,确保我们的业务逻辑不会因为AI服务的“波动”或我们自身代码的疏忽而崩溃。

简单说,这个指南要解决的就是:当你用ollama-python构建AI应用时,如何通过一套系统的单元测试方法,给你的代码加上“安全护栏”,让每一次迭代都信心十足。无论你是想确保聊天机器人每次都返回JSON格式,还是验证文本总结功能不会漏掉关键信息,单元测试都是你不可或缺的工程化工具。

2. 测试策略设计:从模拟到真实,构建多层防御网

直接对真实的Ollama服务进行测试听起来很直接,但存在几个致命问题:速度慢、依赖网络、消耗资源(你的显卡风扇会狂转),并且可能因为模型本身输出的自然波动导致测试时而过不了。因此,一个成熟的测试策略必须是分层的。

2.1 核心策略:Mock(模拟)为王,集成测试点睛

我们的主战场是 单元测试 ,核心思想是“隔离”。我们要测试的是我们自己的函数和类,而不是Ollama服务或底层模型。因此, Mock(模拟) 是首要技术。Python的 unittest.mock 模块是我们的利器。我们会模拟 ollama 模块的 chat generate 等方法,让它们返回我们预设好的、固定的响应数据。这样,测试就能瞬间完成,且结果100%可预测,完美符合单元测试“快速、独立、可重复”的要求。

但是,只做Mock测试就像只做了纸上谈兵。我们还需要 集成测试 来验证整个链条是否通畅。这部分测试会使用一个轻量级的、专门用于测试的模型(比如Ollama官方提供的 tinyllama phi ),针对关键业务流程进行真实调用。这类测试不需要全覆盖,只针对核心的、与Ollama交互最密切的几处集成点。它们运行频率较低(比如每晚或发布前),目的是确保我们的Mock场景没有偏离现实太远。

2.2 测试金字塔与关注点分离

遵循测试金字塔模型,我们构建的测试套件应该是这样的:

  • 底层(最多) :纯逻辑单元测试。测试那些处理AI响应数据的工具函数,比如解析JSON、清洗文本、计算token数量的函数。这些测试不依赖任何外部模块,速度极快。
  • 中层(重点) :Mock单元测试。测试那些包含了 ollama.chat() 调用的业务函数。我们Mock掉ollama,只验证我们的代码在收到特定响应后,逻辑处理是否正确。这是本指南的核心。
  • 高层(较少) :集成测试。测试从发起请求到收到真实模型响应的完整流程,验证环境配置、网络连通性和基础功能。
  • 顶层(最少) :端到端(E2E)测试。模拟真实用户场景,但对于AI交互项目,这类测试成本高、稳定性差,需谨慎使用。

2.3 测试用例设计思路

针对AI交互,我们的测试用例要覆盖以下几个关键维度:

  1. 成功路径 :模拟AI返回一个完美的、符合预期的答案,验证我们的业务逻辑能正确解析并输出。
  2. 边界与异常响应
    • 空响应 :AI什么也没返回,或返回了空字符串。
    • 畸形格式 :我们期望JSON,AI返回了一段混乱的文本。
    • 部分缺失 :期望的字段在响应中不存在。
    • 长文本与截断 :响应内容极长,测试我们的处理逻辑是否会导致内存或性能问题。
  3. 错误处理 :模拟ollama客户端抛出各种异常(如连接错误、超时、模型未找到等),验证我们的代码是否有健壮的容错机制(如重试、降级、友好错误提示)。
  4. 参数传递 :验证我们传递给 ollama.chat() 的参数(如 model , messages , stream , options )是否正确无误。

3. 环境搭建与工具链配置

工欲善其事,必先利其器。一个高效的测试环境能让你事半功倍。

3.1 项目结构与依赖管理

假设你的项目结构如下:

your_ai_project/
├── src/
│   ├── __init__.py
│   ├── ai_client.py       # 封装ollama交互的核心类
│   └── processors.py      # 处理AI响应的工具函数
├── tests/
│   ├── __init__.py
│   ├── conftest.py        # pytest全局配置、夹具
│   ├── unit/
│   │   ├── test_ai_client.py
│   │   └── test_processors.py
│   └── integration/
│       └── test_ollama_integration.py
├── pyproject.toml         # 使用现代项目配置,管理依赖
└── .env.example           # 环境变量示例

pyproject.toml 中定义开发依赖:

[project]
name = "your-ai-project"
dependencies = [
    "ollama>=0.1.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0.0",
    "pytest-mock>=3.10.0",
    "pytest-asyncio>=0.21.0", # 如果你用异步
    "pytest-cov>=4.0.0",      # 代码覆盖率
    "httpx>=0.24.0",          # 用于模拟HTTP请求(更深层的Mock)
]

使用 pip install -e .[dev] 安装所有依赖。

3.2 Pytest与Mock配置

pytest 是目前Python社区事实上的标准测试框架,比 unittest 更简洁灵活。 pytest-mock 插件提供了 mocker 夹具,让Mock操作更简单。

tests/conftest.py 中,我们可以设置一些全局的测试夹具(fixture),比如一个预配置好的AI客户端实例,或者一些通用的模拟响应。

# tests/conftest.py
import pytest
from unittest.mock import AsyncMock, Mock
import json

@pytest.fixture
def mock_ollama_chat_response():
    """返回一个标准的、成功的聊天模拟响应。"""
    return {
        'model': 'llama3:latest',
        'created_at': '2024-01-01T00:00:00.000Z',
        'message': {
            'role': 'assistant',
            'content': '{"answer": "42", "confidence": 0.95}', # 假设我们期望AI返回JSON字符串
        },
        'done': True,
    }

@pytest.fixture
def mock_ollama_client(mocker, mock_ollama_chat_response):
    """提供一个模拟的ollama客户端。"""
    # 模拟整个ollama模块的chat属性
    mock_chat = mocker.patch('ollama.chat', autospec=True)
    # 设置默认返回值
    mock_chat.return_value = mock_ollama_chat_response
    return mock_chat

注意 autospec=True 参数非常重要。它会根据原始对象( ollama.chat )的签名来创建Mock对象,这样如果你错误地调用了不存在的方法或参数,测试就会失败,这能帮你提前发现接口变更带来的问题。

3.3 轻量级测试模型准备

对于集成测试,你需要一个能在测试机上快速加载的模型。Ollama官方的 tinyllama (约1.1B参数)或 phi (约2.7B参数)是绝佳选择。它们体积小,加载快,虽然能力有限,但足以验证“请求-响应”这个通路是否正常。

在运行集成测试前,确保已经拉取并安装了测试模型:

ollama pull tinyllama

然后,在你的集成测试配置或环境变量中,指定使用 model='tinyllama'

4. 核心单元测试实践:Mocking ollama-python

现在进入实战环节。我们将封装一个简单的 AIClient 类,并为其编写完整的单元测试。

4.1 创建被测试的业务类

首先,在 src/ai_client.py 中创建一个与Ollama交互的客户端。

# src/ai_client.py
import ollama
import json
import logging
from typing import Dict, Any, Optional

logger = logging.getLogger(__name__)

class AIClient:
    def __init__(self, model: str = 'llama3:latest', host: str = 'http://localhost:11434'):
        self.model = model
        self.host = host
        # 注意:ollama客户端通常通过环境变量或全局设置host,这里为演示封装

    def get_structured_answer(self, user_question: str) -> Dict[str, Any]:
        """
        向AI提问,并期望得到一个结构化的JSON答案。
        这是一个典型的业务场景。
        """
        messages = [
            {'role': 'system', 'content': '你总是以JSON格式回答,包含"answer"和"confidence"两个键。'},
            {'role': 'user', 'content': user_question}
        ]

        try:
            response = ollama.chat(
                model=self.model,
                messages=messages,
                options={'temperature': 0.1} # 低温度使输出更稳定,适合测试
            )
            ai_content = response['message']['content']
            logger.debug(f"AI原始响应: {ai_content}")

            # 尝试解析JSON
            parsed = json.loads(ai_content.strip())
            # 验证结构
            if 'answer' in parsed and 'confidence' in parsed:
                return parsed
            else:
                logger.error(f"AI返回JSON结构缺失关键字段: {parsed}")
                return {'answer': '解析失败', 'confidence': 0.0}

        except json.JSONDecodeError as e:
            logger.error(f"AI返回内容不是有效JSON: {ai_content}, 错误: {e}")
            return {'answer': '无效的JSON格式', 'confidence': 0.0}
        except KeyError as e:
            logger.error(f"AI响应格式意外,缺少字段: {e}, 响应: {response}")
            return {'answer': '响应格式错误', 'confidence': 0.0}
        except Exception as e:
            logger.error(f"调用Ollama API时发生未知错误: {e}")
            return {'answer': '服务内部错误', 'confidence': 0.0}

    async def get_structured_answer_async(self, user_question: str) -> Dict[str, Any]:
        """异步版本的获取答案方法。ollama-python也支持异步客户端。"""
        # 实际代码中会使用async版本的ollama客户端,这里省略细节。
        # 用于演示异步方法的测试。
        pass

4.2 编写Mock单元测试

接下来,在 tests/unit/test_ai_client.py 中为这个类编写测试。

# tests/unit/test_ai_client.py
import pytest
import json
from unittest.mock import patch, MagicMock
from src.ai_client import AIClient

class TestAIClient:
    """测试AIClient类"""

    @pytest.fixture
    def client(self):
        """提供一个测试用的客户端实例。"""
        return AIClient(model='test-model')

    def test_get_structured_answer_success(self, client, mocker):
        """
        测试成功路径:AI返回了格式正确的JSON。
        这是最核心的测试。
        """
        # 1. 准备模拟数据
        expected_answer = "42"
        expected_confidence = 0.95
        mock_ai_response_content = json.dumps({
            "answer": expected_answer,
            "confidence": expected_confidence
        })

        mock_ollama_response = {
            'model': 'test-model',
            'message': {'role': 'assistant', 'content': mock_ai_response_content},
            'done': True
        }

        # 2. 使用mocker.patch模拟ollama.chat函数
        mock_chat = mocker.patch('ollama.chat')
        mock_chat.return_value = mock_ollama_response

        # 3. 执行被测试的函数
        result = client.get_structured_answer("生命的意义是什么?")

        # 4. 进行断言(Assertions)
        # 4.1 验证ollama.chat被正确调用了一次
        mock_chat.assert_called_once()
        call_args = mock_chat.call_args

        # 4.2 验证调用参数
        assert call_args.kwargs['model'] == 'test-model'
        messages = call_args.kwargs['messages']
        assert len(messages) == 2
        assert messages[0]['role'] == 'system'
        assert 'JSON' in messages[0]['content']
        assert messages[1]['content'] == "生命的意义是什么?"
        assert call_args.kwargs['options'] == {'temperature': 0.1}

        # 4.3 验证函数返回值
        assert result['answer'] == expected_answer
        assert result['confidence'] == expected_confidence

    def test_get_structured_answer_invalid_json(self, client, mocker):
        """
        测试异常路径:AI返回了非JSON内容。
        验证我们的错误处理逻辑。
        """
        # 模拟AI返回了一段普通文本
        mock_ollama_response = {
            'message': {'content': '这是一个纯文本回答,不是JSON。'},
            'done': True
        }
        mocker.patch('ollama.chat', return_value=mock_ollama_response)

        result = client.get_structured_answer("任何问题")

        # 期望函数能捕获JSONDecodeError并返回降级结果
        assert result['answer'] == '无效的JSON格式'
        assert result['confidence'] == 0.0

    def test_get_structured_answer_missing_fields(self, client, mocker):
        """
        测试异常路径:AI返回的JSON缺少约定字段。
        """
        # 模拟AI返回了JSON,但结构不对
        mock_ollama_response = {
            'message': {'content': '{"reply": "好的"}',}, # 缺少answer和confidence
            'done': True
        }
        mocker.patch('ollama.chat', return_value=mock_ollama_response)

        result = client.get_structured_answer("任何问题")

        assert result['answer'] == '解析失败'
        assert result['confidence'] == 0.0

    def test_get_structured_answer_empty_response(self, client, mocker):
        """
        测试边界情况:AI返回空内容或None。
        """
        # 情况1:content为空字符串
        mock_ollama_response_1 = {'message': {'content': ''}, 'done': True}
        mocker.patch('ollama.chat', return_value=mock_ollama_response_1)
        result1 = client.get_structured_answer("问题1")
        assert result1['answer'] == '无效的JSON格式' # 空字符串解析JSON会失败

        # 情况2:整个message为None或缺失(模拟极端情况)
        # 我们需要模拟ollama.chat返回一个没有'message'键的字典,这会触发KeyError
        mock_ollama_response_2 = {'some_other_key': 'value'}
        mocker.patch('ollama.chat', return_value=mock_ollama_response_2)
        result2 = client.get_structured_answer("问题2")
        assert result2['answer'] == '响应格式错误'

    def test_get_structured_answer_api_exception(self, client, mocker):
        """
        测试异常路径:ollama.chat调用本身抛出异常(如连接错误)。
        """
        # 模拟ollama.chat抛出一个连接超时异常
        mocker.patch('ollama.chat', side_effect=ConnectionError("连接超时"))

        result = client.get_structured_answer("重要问题")

        # 验证我们的函数捕获了通用异常并返回了降级结果
        assert result['answer'] == '服务内部错误'
        assert result['confidence'] == 0.0

实操心得 :在Mock测试中, side_effect 是一个极其强大的工具。你可以用它来模拟函数抛出异常、返回一个序列的值等复杂行为。比如 side_effect=[resp1, resp2, Exception(...)] ,可以精确模拟重试逻辑中的成功、失败场景。

4.3 测试异步交互

如果你的项目使用了异步的ollama客户端(例如 async with ollama.AsyncClient() as client: ),测试方法类似,但需要使用 pytest-asyncio AsyncMock

# tests/unit/test_ai_client_async.py
import pytest
import pytest_asyncio
from unittest.mock import AsyncMock, patch
from src.ai_client import AIClient # 假设我们添加了异步方法

@pytest.mark.asyncio
class TestAIClientAsync:
    @pytest.fixture
    def async_client(self):
        return AIClient()

    @pytest.mark.asyncio
    async def test_async_method_success(self, async_client, mocker):
        # 创建AsyncMock来模拟异步客户端的方法
        mock_async_chat = AsyncMock()
        mock_async_chat.return_value = {
            'message': {'content': '{"answer": "async test", "confidence": 1.0}'}
        }

        # 注意patch路径,假设我们有一个_async_client内部属性
        mocker.patch.object(async_client, '_async_chat', new=mock_async_chat)

        # 调用异步方法
        result = await async_client.get_structured_answer_async("test question")
        assert result['answer'] == 'async test'
        # 验证异步方法被await了
        mock_async_chat.assert_awaited_once()

5. 集成测试与真实调用验证

单元测试给了我们信心,但最终还是要和真实世界碰一碰。集成测试就是这座桥梁。

5.1 编写轻量级集成测试

tests/integration/test_ollama_integration.py 中:

# tests/integration/test_ollama_integration.py
import pytest
import ollama
import time

# 标记为集成测试,方便用pytest -m integration单独运行
@pytest.mark.integration
@pytest.mark.slow
class TestOllamaIntegration:
    """与真实Ollama服务交互的集成测试。"""

    @pytest.fixture(scope="class")
    def test_model(self):
        """指定集成测试使用的轻量模型。"""
        return 'tinyllama' # 或 'phi'

    def test_ollama_service_running(self, test_model):
        """基础健康检查:Ollama服务是否可访问,测试模型是否已拉取。"""
        try:
            # 列出本地模型,检查测试模型是否存在
            models = ollama.list()
            model_names = [m['name'] for m in models.get('models', [])]
            assert test_model in model_names, f"测试模型 {test_model} 未找到,请先运行 'ollama pull {test_model}'"
        except Exception as e:
            pytest.fail(f"无法连接Ollama服务,请确保服务已启动。错误: {e}")

    def test_basic_chat_completion(self, test_model):
        """测试最基本的聊天完成功能。"""
        # 使用一个非常简单、确定的提示词
        response = ollama.chat(
            model=test_model,
            messages=[{'role': 'user', 'content': '请只说单词:Hello'}],
            options={'temperature': 0.0, 'seed': 42} # 温度设为0,固定种子,尽可能使输出确定
        )
        content = response['message']['content'].strip()
        # 断言:响应应该包含“Hello”,我们不要求100%精确,因为模型可能有微小波动
        # 这是集成测试与单元测试的关键区别:断言更宽松。
        assert 'Hello' in content or 'hello' in content, f"预期响应包含'Hello',实际得到: {content}"
        assert response['done'] is True

    def test_streaming_response(self, test_model):
        """测试流式响应功能。"""
        stream_generator = ollama.chat(
            model=test_model,
            messages=[{'role': 'user', 'content': '用三个词描述天空。'}],
            stream=True
        )
        full_response = ''
        for chunk in stream_generator:
            if 'message' in chunk and 'content' in chunk['message']:
                full_response += chunk['message']['content']

        # 验证我们确实以流的形式收到了数据
        assert len(full_response) > 0
        # 可以进一步验证响应的大致长度或包含特定词汇
        assert len(full_response.split()) >= 1

5.2 集成测试的运行与管理

集成测试不应该成为你快速开发流程的负担。建议:

  • 使用pytest标记 :如上例所示,用 @pytest.mark.integration @pytest.mark.slow 标记它们。
  • 在CI/CD中分离 :在GitHub Actions/GitLab CI等中,将单元测试作为每次提交的必跑项,而集成测试可以安排在夜间定时任务或发布前的流水线阶段。
  • 环境隔离 :确保CI环境中有可用的Ollama服务和测试模型。可以使用Docker容器来提供稳定的测试环境。
  • 处理非确定性 :集成测试的断言要“宽松而智能”。不要断言确切的字符串,而是断言响应的结构、包含的关键词、类型、长度范围等。可以使用 pytest.approx 进行数值比较,或使用正则表达式进行模式匹配。

6. 高级技巧与最佳实践

掌握了基础测试后,这些高级技巧能让你的测试更健壮、更高效。

6.1 参数化测试:覆盖多种输入场景

使用 @pytest.mark.parametrize 可以轻松地用多组数据测试同一个函数,避免写大量重复的测试方法。

# tests/unit/test_processors.py
import pytest
from src.processors import extract_json_from_text # 假设有这样一个处理函数

class TestProcessors:
    @pytest.mark.parametrize("input_text, expected_output", [
        # (输入文本, 期望提取出的JSON字符串或None)
        ('前缀 {"key": "value"} 后缀', '{"key": "value"}'),
        ('没有JSON的文本', None),
        ('多段JSON,取第一段 {"a":1} 忽略 {"b":2}', '{"a":1}'),
        ('```json\n{"code": 200}\n```', '{"code": 200}'), # 处理代码块
        ('', None), # 空输入
        ('{无效的 json', None), # 无效JSON
    ])
    def test_extract_json_from_text(self, input_text, expected_output):
        result = extract_json_from_text(input_text)
        assert result == expected_output

6.2 测试覆盖率与质量门禁

知道测试了多少代码至关重要。使用 pytest-cov 生成覆盖率报告。

# 运行测试并生成终端报告
pytest --cov=src --cov-report=term-missing

# 生成HTML报告,便于详细查看
pytest --cov=src --cov-report=html

打开生成的 htmlcov/index.html ,你可以直观地看到哪些行被测试覆盖了(绿色),哪些没有(红色)。 不要盲目追求100%覆盖率 ,但核心业务逻辑(如 ai_client.py 中的错误处理、解析逻辑)应尽可能覆盖。在CI流水线中,可以设置覆盖率门槛(如 --cov-fail-under=80 ),低于此值则构建失败。

6.3 Mock的精准控制:spec, autospec与side_effect

  • spec / autospec :如前所述,它们让Mock对象更像真实对象,避免你错误地使用已不存在的API。 强烈推荐始终使用 autospec=True
  • side_effect :除了模拟异常,还可以模拟多次调用的不同返回值。
    # 模拟一个需要重试的场景:第一次调用超时,第二次成功
    mock_func = mocker.patch('some.module.func')
    mock_func.side_effect = [TimeoutError(), {'status': 'success'}]
    
    # 第一次调用
    with pytest.raises(TimeoutError):
        call_func()
    # 第二次调用(在重试逻辑中)
    result = call_func() # 会得到 {'status': 'success'}
    

6.4 测试夹具(Fixture)的组织与复用

将常用的Mock数据、客户端实例等定义为 @pytest.fixture ,可以极大提升测试代码的整洁度和复用性。将这些夹具放在 tests/conftest.py 中,它们会自动对所有测试文件可用。

# tests/conftest.py
import pytest
import json

@pytest.fixture
def valid_ai_json_response():
    return {
        'model': 'test',
        'message': {
            'role': 'assistant',
            'content': json.dumps({"action": "greet", "text": "Hello"})
        },
        'done': True
    }

@pytest.fixture
def ai_client_with_mock(mocker, valid_ai_json_response):
    """提供一个已经配置好Mock响应的AIClient实例。"""
    from src.ai_client import AIClient
    client = AIClient()
    mocker.patch.object(client, '_call_ollama', return_value=valid_ai_json_response)
    return client

7. 常见问题排查与调试技巧

即使有了完善的测试,在编写和调试过程中还是会遇到各种问题。

7.1 Mock没有生效?

这是最常见的问题。原因和解决方案如下表:

问题现象 可能原因 解决方案
测试调用了真实API Mock的路径( patch 的目标)不对。 使用 print(ollama.chat.__module__) 查看函数实际所在模块,确保 patch 路径完全一致。对于类方法,使用 mocker.patch.object(instance, 'method_name')
Mock对象行为不符合预期 Mock设置过于宽泛,或者被意外覆盖。 在测试开始时用 mocker.stopall() 清理之前的mock。使用 autospec 确保Mock签名正确。
异步Mock没被await 使用了普通的 Mock 而不是 AsyncMock 对于异步函数,必须使用 from unittest.mock import AsyncMock

7.2 测试依赖外部状态?

比如测试函数会读取环境变量或配置文件。

  • 解决方案 :在测试中使用 mocker.patch.dict 来临时修改 os.environ ,或者Mock配置文件读取函数。
    def test_with_env_var(mocker):
        with mocker.patch.dict('os.environ', {'OLLAMA_HOST': 'http://test:11434'}):
            client = AIClient()
            # 此时client初始化会使用 test host
            assert client.host == 'http://test:11434'
    

7.3 集成测试不稳定(Flaky Tests)?

由于模型输出的非确定性,集成测试有时过有时不过。

  • 策略1:提高确定性 :设置 temperature=0 和固定的 seed 。对于支持“JSON模式”的模型(如Llama 3.1),强制其返回JSON。
  • 策略2:放宽断言 :不要断言精确字符串。断言响应类型是字符串、非空、包含某个关键词、是有效的JSON等。
  • 策略3:重试机制 :对于非核心的集成测试,可以添加简单的重试逻辑(但需谨慎,避免掩盖真正的问题)。
  • 策略4:标记并管理 :用 @pytest.mark.flaky(reruns=2) (需要 pytest-rerunfailures 插件)让失败的测试自动重跑几次。或者直接将其标记为 @pytest.mark.xfail ,预期它会不稳定,不阻塞CI。

7.4 测试代码本身变得复杂难维护?

测试代码也是代码,需要保持整洁。

  • 遵循DRY原则 :将通用的准备步骤(Arrange)提取到夹具(fixture)中。
  • 使用工厂函数 :对于创建复杂测试数据,使用工厂函数而非在测试中硬编码。
  • 清晰的命名 :测试函数名应该像文档一样,如 test_get_answer_returns_none_when_api_times_out
  • 单一职责 :一个测试函数只测试一个特定的行为或场景。

为ollama-python交互层编写单元测试,初期看起来像是额外的工作,但它所带来的稳定性和开发信心是无可替代的。它迫使你思考边界情况,设计更健壮的接口,并最终构建出能够应对AI固有不确定性的、真正可靠的应用程序。从今天开始,为你下一个调用 ollama.chat() 的函数写一个简单的测试吧,你会发现,代码的未来变得清晰多了。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐