LLM API

LLM API 请求体参数

  • n:默认1,每个prompt生成n个结果。
  • best_of:默认1,在服务器端生成best_of个完成结果,并返回 “最佳” 结果,结果无法流式传输。与n一起使用时,best_of控制候选完成结果的数量,而n指定要返回的数量(此时best_of必须大于n)。
  • logit_bias:修改指定token出现在完成结果中的可能性。接受一个JSON对象,将token(通过token ID指定)映射到 -100 到 100 之间的相关偏差值。 -1 到 1 之间的值应该会降低或增加选择的可能性; -100 或 100 这样的值应该会导致相关token被禁止出现或被唯一选择。 例如,传入{"50256": -100}可以防止生成<|endoftext|>的token。
  • logprobs:最大值5,输出logprobs个最有可能的 token 及其对应概率,例如logprobs为 5,API 将返回 5 个最有可能的词元的列表。
  • frequency_penalty:对新 token 出现频率的惩罚值,范围[-2.0, 2.0]。值 > 0 鼓励模型使用新 token,而值 < 0 鼓励模型重复 token。
  • presence_penalty:是否出现新 token 的惩罚值,范围[-2.0, 2.0]。值 > 0 鼓励模型使用新 token,值 < 0 鼓励模型重复 token。
  • seed:用于生成的随机种子。
  • suffix:用于在生成的文本后添加一段固定的后缀。
  • temperature:默认1,控制采样随机性的浮点数,范围[0, 2]。较低的值使模型更具确定性,较高的值使模型更具随机性。值为 0 表示贪婪采样。
  • top_p:默认1,核采样,模型会考虑概率质量在前 top_p 的 token 的结果。例如,0.1 意味着只考虑概率质量在前 10% 的 token。

示例:

import os
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()
client = OpenAI(
base_url=os.getenv("BAILIAN_API_BASE_URL"),
api_key=os.getenv("BAILIAN_API_KEY")
)

response = client.chat.completions.create(
model=model,
messages=prompt,
max_tokens=500,
temperature=0.7,
stop=["用户:"], # 防止模型生成用户的发言
extra_body={"enable_thinking": False}
)

结构化输出

使用

  1. 定义Json Schema

  2. 指定text.format

    text: { format: { type: "json_schema", "strict": true, "schema": … } }
  3. 处理边界情况

    response = client.responses.create(
    model="gpt-4o-2024-08-06",
    input=[
    {"role": "system", "content": "You are a helpful math tutor. Guide the user through the solution step by step."},
    {"role": "user", "content": "how can I solve 8x + 7 = -23"}
    ],
    text={
    "format": {
    "type": "json_schema",
    "name": "math_response",
    "schema": {
    "type": "object",
    "properties": {
    "steps": {
    "type": "array",
    "items": {
    "type": "object",
    "properties": {
    "explanation": {"type": "string"},
    "output": {"type": "string"}
    },
    "required": ["explanation", "output"],
    "additionalProperties": False
    }
    },
    "final_answer": {"type": "string"}
    },
    "required": ["steps", "final_answer"],
    "additionalProperties": False
    },
    "strict": True
    }
    }
    )

    print(response.output_text)

支持的 Schema

  • String
  • Number
  • Boolean
  • Integer
  • Object
  • Array
  • Enum
  • anyOf

支持的属性

string
  • pattern:正则表达式

  • format:预定义的格式

    • date-time
    • time
    • date
    • duration
    • email
    • hostname
    • ipv4
    • ipv6
    • uuid
number
  • multipleOf:必须是该数的倍数
  • maximum:<=
  • exclusiveMaximum:<
  • minimum:>=
  • exclusiveMinimum:>
array
  • minItems
  • maxItems

Json 模式

text.format设置为:

{ "type": "json_object" }

使用函数调用时,JSON 模式将始终开启。

使用 JSON 模式时,必须始终通过对话中的某些消息(例如通过系统消息)指示模型生成 JSON,否则可能会生成无休止的空白字符流。

response = client.responses.create(
model="gpt-3.5-turbo-0125",
input=[
{"role": "system", "content": "You are a helpful assistant designed to output JSON."},
{"role": "user", "content": "Who won the world series in 2020? Please respond in the format {winner: ...}"}
],
text={"format": {"type": "json_object"}}
)

使用 Tools

在生成模型回复时,可以使用内置的 Tools 来扩展模型的能力,帮助模型从网络或文件中获取更多上下文和信息。

例:

from openai import OpenAI
client = OpenAI()

response = client.responses.create(
model="gpt-4.1",
tools=[{"type": "web_search_preview"}],
input="What was a positive news story from today?"
)

print(response.output_text)

可用的 Tools

  • 函数调用
  • 网络搜索
  • 远程 MCP(Model Context Protocol) 服务
  • 文件搜索
  • 图片生成
  • 代码解释
  • 计算机使用:在计算机上进行各种操作和任务

函数调用

函数定义

函数可以在每个 API 请求的tools参数中设置。

字段 描述
type 必须为 function
name 函数名称 (e.g. get_weather)
description 何时、如何使用函数的细节
parameters 定义函数输入参数的JSON schema
strict 是否对函数调用强制执行严格模式

例:

{
"type": "function",
"name": "get_weather",
"description": "Retrieves current weather for the given location.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country e.g. Bogotá, Colombia"
},
"units": {
"type": "string",
"enum": [
"celsius",
"fahrenheit"
],
"description": "Units the temperature will be returned in."
}
},
"required": [
"location",
"units"
],
"additionalProperties": false
},
"strict": true
}

流式响应

流式响应允许在模型继续生成完整响应的同时,开始打印或处理模型输出的开头部分。

设置stream=True即可使用:

from openai import OpenAI
client = OpenAI()

stream = client.responses.create(
model="gpt-4.1",
input=[
{
"role": "user",
"content": "Say 'double bubble bath' ten times fast.",
},
],
stream=True,
)

for event in stream:
print(event)

Responses API 使用语义事件进行流式传输,每个事件都按照预定义的模式进行类型标注。完整的事件类型列表,请参阅流式传输的 API 参考文档

Agent - Agno

Agent 创建

简单Agent:

from agno.agent import Agent
from agno.models.anthropic import Claude
from agno.tools.yfinance import YFinanceTools

agent = Agent(
model=Claude(id="claude-sonnet-4-20250514"),
tools=[YFinanceTools(stock_price=True)],
instructions="Use tables to display data. Don't include any other text.",
markdown=True,
)
agent.print_response("What is the stock price of Apple?", stream=True)

OpenAI Like 模型

from os import getenv
from agno.agent import Agent, RunResponse
from agno.models.openai.like import OpenAILike

agent = Agent(
model=OpenAILike(
id="mistralai/Mixtral-8x7B-Instruct-v0.1",
api_key=getenv("TOGETHER_API_KEY"),
base_url="https://api.together.xyz/v1",
)
)

# Print the response in the terminal
agent.print_response("Share a 2 sentence horror story.")

运行 Agent

agno 1.6.0 开始,run()将返回 RunResponseEvent 的迭代对象。

from typing import Iterator
from agno.agent import Agent, RunResponseEvent
from agno.models.openai import OpenAIChat
from agno.utils.pprint import pprint_run_response

agent = Agent(model=OpenAIChat(id="gpt-4-mini"))

# Run agent and return the response as a stream
response_stream: Iterator[RunResponseEvent] = agent.run(
"Tell me a 5 second short story about a lion",
stream=True
)

# Print the response stream in markdown format
pprint_run_response(response_stream, markdown=True)

Agent State

Agno 提供了状态管理系统,只需添加变量到 session_state,以及设置add_state_in_messages=True

示例:

from agno.agent import Agent
from agno.models.openai import OpenAIChat

# Define a tool that adds an item to the shopping list
def add_item(agent: Agent, item: str) -> str:
"""Add an item to the shopping list."""
agent.session_state["shopping_list"].append(item)
return f"The shopping list is now {agent.session_state['shopping_list']}"


# Create an Agent that maintains state
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
# Initialize the session state with a counter starting at 0
session_state={"shopping_list": []},
tools=[add_item],
# You can use variables from the session state in the instructions
instructions="Current state (shopping list) is: {shopping_list}",
# Important: Add the state to the messages
add_state_in_messages=True,
markdown=True,
)

# Example usage
agent.print_response("Add milk, eggs, and bread to the shopping list", stream=True)
print(f"Final session state: {agent.session_state}")

跨对话保持状态

示例:

from textwrap import dedent

from agno.agent import Agent
from agno.models.openai import OpenAIChat


# Define tools to manage our shopping list
def add_item(agent: Agent, item: str) -> str:
"""Add an item to the shopping list and return confirmation."""
# Add the item if it's not already in the list
if item.lower() not in [i.lower() for i in agent.session_state["shopping_list"]]:
agent.session_state["shopping_list"].append(item)
return f"Added '{item}' to the shopping list"
else:
return f"'{item}' is already in the shopping list"


def remove_item(agent: Agent, item: str) -> str:
"""Remove an item from the shopping list by name."""
# Case-insensitive search
for i, list_item in enumerate(agent.session_state["shopping_list"]):
if list_item.lower() == item.lower():
agent.session_state["shopping_list"].pop(i)
return f"Removed '{list_item}' from the shopping list"

return f"'{item}' was not found in the shopping list"


def list_items(agent: Agent) -> str:
"""List all items in the shopping list."""
shopping_list = agent.session_state["shopping_list"]

if not shopping_list:
return "The shopping list is empty."

items_text = "\n".join([f"- {item}" for item in shopping_list])
return f"Current shopping list:\n{items_text}"


# Create a Shopping List Manager Agent that maintains state
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
# Initialize the session state with an empty shopping list
session_state={"shopping_list": []},
tools=[add_item, remove_item, list_items],
# You can use variables from the session state in the instructions
instructions=dedent("""\
Your job is to manage a shopping list.

The shopping list starts empty. You can add items, remove items by name, and list all items.

Current shopping list: {shopping_list}
"""),
show_tool_calls=True,
add_state_in_messages=True,
markdown=True,
)

# Example usage
agent.print_response("Add milk, eggs, and bread to the shopping list", stream=True)
print(f"Session state: {agent.session_state}")

agent.print_response("I got bread", stream=True)
print(f"Session state: {agent.session_state}")

agent.print_response("I need apples and oranges", stream=True)
print(f"Session state: {agent.session_state}")

agent.print_response("whats on my list?", stream=True)
print(f"Session state: {agent.session_state}")

agent.print_response("Clear everything from my list and start over with just bananas and yogurt", stream=True)
print(f"Session state: {agent.session_state}")

状态持久化保存

需要设置storage

示例:

"""Run `pip install agno openai sqlalchemy` to install dependencies."""

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.storage.sqlite import SqliteStorage


# Define a tool that adds an item to the shopping list
def add_item(agent: Agent, item: str) -> str:
"""Add an item to the shopping list."""
if item not in agent.session_state["shopping_list"]:
agent.session_state["shopping_list"].append(item)
return f"The shopping list is now {agent.session_state['shopping_list']}"


agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
# Fix the session id to continue the same session across execution cycles
session_id="fixed_id_for_demo",
# Initialize the session state with an empty shopping list
session_state={"shopping_list": []},
# Add a tool that adds an item to the shopping list
tools=[add_item],
# Store the session state in a SQLite database
storage=SqliteStorage(table_name="agent_sessions", db_file="tmp/data.db"),
# Add the current shopping list from the state in the instructions
instructions="Current shopping list is: {shopping_list}",
# Important: Set `add_state_in_messages=True`
# to make `{shopping_list}` available in the instructions
add_state_in_messages=True,
markdown=True,
)

# Example usage
agent.print_response("What's on my shopping list?", stream=True)
print(f"Session state: {agent.session_state}")
agent.print_response("Add milk, eggs, and bread", stream=True)
print(f"Session state: {agent.session_state}")

Memory

Agno 提供三种 memory

  1. Session Storage (chat history and session state):将 Agent 的会话以及session_state保存在数据库中,并使 Agent 能够进行多轮对话。
  2. User Memories (user preferences):Agent 可以存储它通过对话了解到的有关用户的见解和事实。
  3. Session Summaries (chat summary):Agent 可以存储会话的压缩表示形式,在聊天历史记录过长时非常有用。

示例代码

from agno.agent import Agent
from agno.memory.v2.db.sqlite import SqliteMemoryDb
from agno.memory.v2.memory import Memory
from agno.models.openai import OpenAIChat
from agno.storage.sqlite import SqliteStorage
from rich.pretty import pprint

# UserId for the memories
user_id = "ava"
# Database file for memory and storage
db_file = "tmp/agent.db"

# Initialize memory.v2
memory = Memory(
# Use any model for creating memories
model=OpenAIChat(id="gpt-4.1"),
db=SqliteMemoryDb(table_name="user_memories", db_file=db_file),
)
# Initialize storage
storage = SqliteStorage(table_name="agent_sessions", db_file=db_file)

# Initialize Agent
memory_agent = Agent(
model=OpenAIChat(id="gpt-4.1"),
# Store memories in a database
memory=memory,
# Give the Agent the ability to update memories
enable_agentic_memory=True,
# OR - Run the MemoryManager after each response
enable_user_memories=True,
# Store the chat history in the database
storage=storage,
# Add the chat history to the messages
add_history_to_messages=True,
# Number of history runs
num_history_runs=3,
markdown=True,
)

memory.clear()
memory_agent.print_response(
"My name is Ava and I like to ski.",
user_id=user_id,
stream=True,
stream_intermediate_steps=True,
)
print("Memories about Ava:")
pprint(memory.get_user_memories(user_id=user_id))

memory_agent.print_response(
"I live in san francisco, where should i move within a 4 hour drive?",
user_id=user_id,
stream=True,
stream_intermediate_steps=True,
)
print("Memories about Ava:")
pprint(memory.get_user_memories(user_id=user_id))

会话总结

from agno.agent import Agent
from agno.memory.v2.db.sqlite import SqliteMemoryDb
from agno.memory.v2.memory import Memory
from agno.models.google.gemini import Gemini

memory_db = SqliteMemoryDb(table_name="memory", db_file="tmp/memory.db")
memory = Memory(db=memory_db)

user_id = "jon_hamm@example.com"
session_id = "1001"

agent = Agent(
model=Gemini(id="gemini-2.0-flash-exp"),
memory=memory,
enable_session_summaries=True,
)

agent.print_response(
"What can you tell me about quantum computing?",
stream=True,
user_id=user_id,
session_id=session_id,
)

agent.print_response(
"I would also like to know about LLMs?",
stream=True,
user_id=user_id,
session_id=session_id
)

session_summary = memory.get_session_summary(
user_id=user_id, session_id=session_id
)
print(f"Session summary: {session_summary.summary}\n")

Tools

使用:

from agno.agent import Agent

agent = Agent(
# Add functions or Toolkits
tools=[...],
# Show tool calls in the Agent response
show_tool_calls=True
)

使用已有 toolkit

from agno.agent import Agent
from agno.tools.duckduckgo import DuckDuckGoTools

agent = Agent(tools=[DuckDuckGoTools()], show_tool_calls=True, markdown=True)
agent.print_response("Whats happening in France?", stream=True)

自定义 Tools

import json
import httpx

from agno.agent import Agent

def get_top_hackernews_stories(num_stories: int = 10) -> str:
"""Use this function to get top stories from Hacker News.

Args:
num_stories (int): Number of stories to return. Defaults to 10.

Returns:
str: JSON string of top stories.
"""

# Fetch top story IDs
response = httpx.get('https://hacker-news.firebaseio.com/v0/topstories.json')
story_ids = response.json()

# Fetch story details
stories = []
for story_id in story_ids[:num_stories]:
story_response = httpx.get(f'https://hacker-news.firebaseio.com/v0/item/{story_id}.json')
story = story_response.json()
if "text" in story:
story.pop("text", None)
stories.append(story)
return json.dumps(stories)

agent = Agent(tools=[get_top_hackernews_stories], show_tool_calls=True, markdown=True)
agent.print_response("Summarize the top 5 stories on hackernews?", stream=True)

结构化输出

from typing import List
from rich.pretty import pprint
from pydantic import BaseModel, Field
from agno.agent import Agent, RunResponse
from agno.models.openai import OpenAIChat

class MovieScript(BaseModel):
setting: str = Field(..., description="Provide a nice setting for a blockbuster movie.")
ending: str = Field(..., description="Ending of the movie. If not available, provide a happy ending.")
genre: str = Field(
..., description="Genre of the movie. If not available, select action, thriller or romantic comedy."
)
name: str = Field(..., description="Give a name to this movie")
characters: List[str] = Field(..., description="Name of characters for this movie.")
storyline: str = Field(..., description="3 sentence storyline for the movie. Make it exciting!")

# Agent that uses JSON mode
json_mode_agent = Agent(
model=OpenAIChat(id="gpt-4o"),
description="You write movie scripts.",
response_model=MovieScript,
use_json_mode=True,
)
json_mode_agent.print_response("New York")

# Agent that uses structured outputs
structured_output_agent = Agent(
model=OpenAIChat(id="gpt-4o"),
description="You write movie scripts.",
response_model=MovieScript,
)

structured_output_agent.print_response("New York")

FastAPI

FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,专为在 Python 中构建 RESTful API 而设计。

FastAPI 基本路由

每个路由都映射到应用程序中的一个函数,用于处理特定的 HTTP 请求,并返回相应的响应。

根路径路由

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
return {"Hello": "World"}
  • @app.get("/"):使用 @app.get 装饰器创建一个处理根路径的路由。

路径参数

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
  • 其中 {item_id} 是路径参数,对应函数参数 item_id
  • q是查询参数

使用浏览器访问 http://127.0.0.1:8000/items/5?q=runoob,将会看到如下 JSON 响应:

{"item_id": 5, "q": "runoob"}

请求体

此处使用 Pydantic 模型 Item 定义了一个请求体,更多 Pydantic 介绍参考:FastAPI Pydantic 模型

from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None

@app.post("/items/")
def create_item(item: Item):
return item

最终返回一个 Pydantic 模型实例,FastAPI 将自动将其转换为 JSON 格式,并作为响应发送给客户端。

使用 Header 和 Cookie 类型注解获取请求头和 Cookie 数据。

from fastapi import Header, Cookie
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
def read_item(user_agent: str = Header(None), session_token: str = Cookie(None)):
return {"User-Agent": user_agent, "Session-Token": session_token}

重定向

使用 RedirectResponse 实现重定向。

from fastapi.responses import RedirectResponse

@app.get("/redirect")
def redirect():
return RedirectResponse(url="/items/")

错误码

使用 HTTPException 抛出异常,返回自定义的状态码和详细信息。

from fastapi import HTTPException

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int):
if item_id == 42:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id}

自定义响应头

使用 JSONResponse 自定义响应头

from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int):
content = {"item_id": item_id}
headers = {"X-Custom-Header": "custom-header-value"}
return JSONResponse(content=content, headers=headers)

路径操作依赖项

依赖项是在路由操作函数执行前或后运行的可复用的函数或对象。在 FastAPI 中,依赖项通常用于两个方面:

  • 预处理(Before)依赖项: 在路由操作函数执行前运行,用于预处理输入数据,验证请求等。
  • 后处理(After)依赖项: 在路由操作函数执行后运行,用于执行一些后处理逻辑,如日志记录、清理等。

预处理

在路由操作函数 read_items 中,通过传入 Depends(common_parameters),我们使用了这个依赖项函数,实现了在路由执行前预处理输入数据的功能。

from fastapi import Depends, FastAPI, HTTPException

app = FastAPI()

# 依赖项函数
def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}

# 路由操作函数
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons

后处理

from fastapi import Depends, FastAPI, HTTPException

app = FastAPI()

# 依赖项函数
def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}

# 路由操作函数
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons

# 后处理函数
async def after_request():
# 这里可以执行一些后处理逻辑,比如记录日志
pass

# 后处理依赖项
@app.get("/items/", response_model=dict)
async def read_items_after(request: dict = Depends(after_request)):
return {"message": "Items returned successfully"}

多个依赖项组合

以下例子中,common_parametersverify_token 是两个不同的依赖项函数,verify_token 依赖于 common_parameters,这种组合依赖项的方式允许我们在路由执行前先验证一些参数,然后在进行身份验证。

from fastapi import Depends, FastAPI, HTTPException

app = FastAPI()

# 依赖项函数1
def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}

# 依赖项函数2
def verify_token(token: str = Depends(common_parameters)):
if token is None:
raise HTTPException(status_code=400, detail="Token required")
return token

# 路由操作函数
@app.get("/items/")
async def read_items(token: dict = Depends(verify_token)):
return token

FastAPI 交互式 API 文档

FastAPI 提供了内置的交互式 API 文档,使开发者能够轻松了解和测试 API 的各个端点。

这个文档是自动生成的,基于 OpenAPI 规范,支持 Swagger UI 和 ReDoc 两种交互式界面。

默认情况下,你可以通过访问 http://127.0.0.1:8000/docs 来打开 Swagger UI 风格的文档:

或者通过 http://127.0.0.1:8000/redoc 来打开 ReDoc 风格的文档。

SSE

服务端推送(Server-Send Events),也称为消息推送或通知推送,是一种允许应用服务器主动将信息发送到客户端的能力。

技术 协议 方向性 复杂度 延迟 适用场景
短轮询 HTTP 双向(伪) 简单状态检测
长轮询 HTTP 双向(伪) 即时消息
WebSocket WS 全双工 游戏/高频交易
SSE HTTP 单向(服务端→客户端) 实时通知/日志流

SSE的核心优势

  • 协议轻量:基于标准HTTP协议,无需额外握手
  • 自动重连:内置断线重连机制(retry字段)
  • 文本友好:天然支持UTF-8文本数据流
  • 浏览器原生支持:现代浏览器100%兼容(IE除外)

FastAPI SSE 示例代码

import datetime
import json
import uuid
from typing import Iterable
import asyncio
from fastapi import FastAPI, Request
from sse_starlette.sse import EventSourceResponse
from starlette.responses import FileResponse

app = FastAPI()

@app.get("/")
async def read_index():
return FileResponse("index.html")

STREAM_DELAY = 1 # second
RETRY_TIMEOUT = 15000 # millisecond

def get_new_messages() -> Iterable:
return [
{
"event": "new_message",
"retry": RETRY_TIMEOUT,
"data": json.dumps(
{
"message": "test message",
"datetime": datetime.datetime.now().isoformat(
sep="T", timespec="auto"
),
}
),
"id": uuid.uuid4(),
}
]

async def event_generator(request: Request):
while True:
if await request.is_disconnected():
break
for message in get_new_messages():
yield message
await asyncio.sleep(STREAM_DELAY)

@app.get("/stream")
async def message_stream(request: Request):
return EventSourceResponse(event_generator(request))

Docker

Docker 是一个开源的应用容器引擎,可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 linux 服务器,也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口(类 IPhone 的 app),并且容器开销极其低。

镜像(Image)与容器(Container)

  • 镜像(Image):容器的静态模板,包含了应用程序运行所需的所有依赖和文件。镜像是不可变的。
  • 容器(Container):镜像的一个运行实例,具有自己的文件系统、进程、网络等,且是动态的。容器从镜像启动,并在运行时保持可变。

镜像仓库(Docker Registry)

镜像仓库 (Docker Registry) 负责存储、管理和分发镜像,并且提供了登录认证能力,建立了仓库的索引。

镜像仓库管理多个 Repository, Repository 通过命名来区分。每个 Repository 包含一个或多个镜像,镜像通过镜像名称和标签来区分。

Dockerfile

Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有指令。

基本结构包括以下几个部分:

  • 基础映像(Base Image):使用 FROM 指令指定基础映像,作为构建镜像的起点。基础映像通常包含了操作系统和一些预装的软件和工具。
  • 构建过程指令:使用一系列指令来描述构建过程,例如 RUN 用于执行命令和安装软件包,COPY 用于拷贝文件和目录,ADD 用于拷贝和提取文件,WORKDIR 用于设置工作目录,等等。
  • 容器启动指令:使用 CMD 或 ENTRYPOINT 指令来定义容器启动时要执行的命令,也就是默认的容器执行命令。

示例

FROM centos7.9.2009
MAINTAINER akuya<123456@qq.com>

# 配置环境以及工作目录
ENV MYPATH /usr/local
WORKDIR $MYPATH

# 安装vim、ipconfig等命令
RUN yum -y install vim
RUN yum -y install net-tools

# 暴露端口
EXPOSE 80

CMD echo $MYPATH
CMD echo "---akuya---"
CMD /bin/bash

构建镜像

# 构建镜像命令
docker build -f Dockerfile -t mycentos:1.0 .

参数:

  • -f:等价于--file,指定 dockerfile 文件
  • -t:等价于--tag,指定输出的镜像文件名:版本号

命令最后一定要加一个.

容器 vs 虚拟机

容器时在 linux 上本机运行,并与其他容器共享主机的内核,它运行的是一个独立的进程,不占用其他任何可执行文件的内存,非常轻量。

虚拟机运行的是一个完整的操作系统,通过虚拟机管理程序对主机资源进行虚拟访问,相比之下需要的资源更多。

卷(Volume)

卷是用于持久化数据的文件系统,可以在容器之间共享和重用。通过使用卷,数据可以在容器停止或删除时仍然保留。

使用数据卷的步骤一般分为两步:

  1. 创建一个数据卷
  2. 使用 -v--mount 参数将数据卷挂载容器指定目录中,这样所有该容器针对该指定目录的写操作都会保存在宿主机上的 Volume 中。

创建 volume

docker volume create my-vol

查看 volume

$ docker volume ls
local my-vol

$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]

删除 volume

删除一个 Volume:

docker volume rm my-vol

删除所有未使用的 Volumes:

docker volume prune

挂载数据卷到容器目录

使用--mount参数:

$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest

source 指定 volumedestination 指定容器内的文件或文件夹。

使用 -v 参数:

$ docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest

-v 参数使用冒号分割 sourcedestination,冒号前半部分是 source,后半部分是 destination

挂载成功后,容器从 /usr/share/nginx/html 目录下读取或写入数据,实际上都是从宿主机的 nginx-vol 数据卷中读取或写入数据。因此 Volumes 或 Bind mounts 也可以看作是容器和宿主机共享文件的一种方式。

启动容器

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

参数:

  • -d: 后台运行容器并返回容器 ID。
  • -it: 交互式运行容器,分配一个伪终端。
  • --name: 给容器指定一个名称。docker run --name my_container ubuntu即运行一个 ubuntu 容器,并将其命名为 my_container。
  • -p: 端口映射,格式为 host_port:container_portdocker run -p 8080:80 nginx即将本地主机的 8080 端口映射到容器内的 80 端口,运行 nginx 容器。
  • -v: 挂载卷,格式为 host_dir:container_dir
  • --rm: 容器停止后自动删除容器。
  • --env-e: 设置环境变量。
  • --network: 指定容器的网络模式。
  • --restart: 容器的重启策略(如 noon-failurealwaysunless-stopped)。
  • -u: 指定用户。

Docker Compose

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 文件(docker-compose.yml)可以配置应用程序的所有服务,然后使用单个命令创建和启动所有服务。

安装

在安装 Docker Compose 前,请确保已安装 Docker Engine

Linux 安装方法

# 下载最新版本的 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 添加可执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 验证安装
docker-compose --version
# 应输出:Docker Compose version v2.23.0

Windows/macOS 安装

Windows 和 macOS 的 Docker Desktop 已包含 Docker Compose,无需单独安装。

核心概念

  1. **服务 (Service)**:一个容器化的应用(如 web 服务器、数据库)
  2. **项目 (Project)**:由一组关联服务组成的完整应用
  3. Compose 文件:定义服务、网络和卷的 YAML 文件

docker-compose.yml 文件结构

version: "3.9"  # Compose 文件格式版本

services: # 定义所有服务
web: # 服务名称
image: nginx:alpine # 使用的镜像
ports:
- "80:80" # 端口映射
volumes:
- ./html:/usr/share/nginx/html # 卷挂载

db:
image: postgres:15
environment: # 环境变量
POSTGRES_PASSWORD: example

volumes: # 定义卷
db-data: # 卷名称

关键字段

字段 说明 示例
version Compose 文件版本 "3.9"
services 定义所有服务
image 使用的 Docker 镜像 nginx:alpine
build 根据 Dockerfile 构建镜像 context: ./dir
ports 端口映射 - "8080:80"
volumes 卷挂载 - ./data:/app/data
environment 设置环境变量 DEBUG: "true"
depends_on 服务依赖关系 - db
networks 加入的网络 - backend

启动应用:

docker-compose up -d

常用命令

命令 说明
docker-compose up 创建并启动所有服务
docker-compose up -d 在后台运行服务
docker-compose down 停止并移除所有容器、网络
docker-compose ps 查看运行中的服务
docker-compose logs 查看服务日志
docker-compose logs -f web 实时查看 web 服务日志
docker-compose build 构建或重新构建服务镜像
docker-compose start 启动已存在的服务
docker-compose stop 停止运行中的服务
docker-compose restart 重启服务
docker-compose exec web sh 进入 web 服务的容器
docker-compose pull 拉取服务的最新镜像
docker-compose config 验证 Compose 文件格式

参考链接

【Docker】Docker Registry(镜像仓库) - 知乎

Docker 数据存储之 Volumes 详解 - 知乎

docker入门(八)—— dockerfile详细介绍,编写dockerfile-CSDN博客

Docker build 命令 | 菜鸟教程

Docker run 命令 | 菜鸟教程

Docker Compose 教程:安装、使用与快速入门 - 锋露 - 博客园

一篇就够!Windows上Docker Desktop安装 + 汉化完整指南(包含解决wsl更新失败方案)_docker汉化-CSDN博客