Flink Agents作为事件驱动型智能体系统的开发框架,不仅继承了Flink引擎分布式、大规模、容错性的结构化数据流式处理能力以及成熟的状态管理机制,还为智能体式人工智能(Agentic AI)的基础组件与功能提供了原生级抽象。这些抽象简化了智能体系统开发的复杂程度,对于开发者来说,能够降低学习难度,提升开发效率。了解这些基础组件,是基于Flink Agents开发事件驱动型智能体系统的必经之路。
1、Chat models(对话模型)
对话模型(Chat models)能让智能体(Agents)与大型语言模型(LLM)进行交互,从而实现自然语言理解、推理与生成功能。在Flink Agents中,对话模型扮演着智能体 “大脑” 的角色:它会处理输入消息,并根据上下文(Context)、提示词(Prompts)及可用工具,生成具有智能性的响应。
1.1 对话模型的创建
要在智能体中使用对话模型(Chat models),需通过装饰器(decorators)(注:本文阐述均基于Python开发语言来说)同时定义连接(connection)与配置(setup),随后通过事件(events)与该模型进行交互。
- @chat_model_connection
@chat_model_connection装饰器(decorators)用于标记一个 “创建对话模型连接” 的方法。该方法通常只需定义一次,即可在多个对话模型配置中共享使用。 - @chat_model_setup
@chat_model_setup装饰器(decorators)用于标记一个 “创建对话模型配置” 的方法。该方法会引用一个(已定义的)连接,并添加对话专属的配置项(如提示词、工具等)。
1.2 对话事件(Chat Events)
对话模型通过内置事件(events)实现通信,核心事件包括:
- ChatRequestEvent(对话请求事件):由 “动作(actions)” 发送,用于向大型语言模型(LLM)请求生成对话结果(chat completion)。
- ChatResponseEvent(对话响应事件):由 “动作(actions)” 接收,包含大型语言模型(LLM)返回的响应内容。
1.3 示例
class MyAgent(Agent):
#定义对话模型连接
@chat_model_connection
@staticmethod
def ollama_connection() -> ResourceDescriptor:
return ResourceDescriptor(
clazz=OllamaChatModelConnection,
base_url="http://localhost:11434",
request_timeout=30.0
)
#定义对话模型配置
@chat_model_setup
@staticmethod
def ollama_chat_model() -> ResourceDescriptor:
return ResourceDescriptor(
clazz=OllamaChatModelSetup,
connection="ollama_connection",
model="qwen3:8b",
temperature=0.7
)
@action(InputEvent)
@staticmethod
def process_input(event: InputEvent, ctx: RunnerContext) -> None:
# Create a chat request with user message
user_message = ChatMessage(
role=MessageRole.USER,
content=f"input: {event.input}"
)
ctx.send_event(
ChatRequestEvent(model="ollama_chat_model", messages=[user_message])
) # 此Action发送对话请求事件
@action(ChatResponseEvent) # 此Action接收对话响应事件
@staticmethod
def process_response(event: ChatResponseEvent, ctx: RunnerContext) -> None:
response_content = event.response.content
# Handle the LLM's response
# Process the response as needed for your use case
1.4 内置的对话模型
- Anthropic:AnthropicChatModelConnection / AnthropicChatModelSetup
- Ollama:OllamaChatModelConnection / OllamaChatModelSetup
- OpenAI:OpenAIChatModelConnection / OpenAIChatModelSetup
- Tongyi:TongyiChatModelConnection / TongyiChatModelSetup
1.5 自定义对话模型
如果你想使用内置对话模型以外的模型,可以扩展基础对话类自行实现!对话模型系统围绕两个主要的抽象类构建而成:BaseChatModelConnection和BaseChatModelSetup。
2、Action(行动)
Action(行动)是一段可执行的代码。每个行动至少监听一种事件类型。当所监听类型的事件发生时,该动作会被触发。动作还可以生成新的事件,以触发其他动作。
在智能体(Agent)中声明Action时,用户可使用@action装饰器修饰智能体类的函数,并将所监听的事件类型声明为装饰器的参数。被修饰的函数签名应为(Event, RunnerContext) -> None
Action示例如1.3节中process_input函数和process_response函数所示。
3、Event(事件)
请注意,这里Event的概念是就智能体内部通信而言的。
Event(事件)是在行动(Actions)之间传递的消息。事件可携带有效负载(payloads)。若多个动作均监听某一事件类型,则单个事件可触发这些动作。
事件包含两种特殊类型:
- InputEvent(输入事件):由框架生成,携带在 “输入字段(input field)” 中到达智能体(agent)的一条输入数据记录。监听 InputEvent 的Acion将成为智能体的入口点(entry points)。
- OutputEvent(输出事件):框架会监听OutputEvent,并将其 “输出字段(output field)” 中的有效负载转换为智能体的输出。Action可通过生成OutputEvent来发送输出数据。
4、RunnerContext(运行时上下文)
RunnerContext是模型上下文的抽象基类,为智能体(agent)执行提供上下文。 运行时上下文支持对事件处理的访问。
- RunnerContext.send_event() # 发送事件
- RunnerContext.short_term_memory() # 获取短期记忆对象
5、Prompts(提示词)
提示词(Prompts)是定义智能体(agents)如何与大型语言模型(LLMs)进行交互的模板。它们提供结构化的指令、上下文信息以及格式规范,这些内容会影响大型语言模型的响应生成。在Flink Agents中,提示词属于 “一等资源”(first-class resources),可在不同智能体与对话模型(chat models)之间进行定义、复用和引用。
Flink Agents支持两种类型的提示词:本地提示词(Local Prompt)和MCP提示词(MCP Prompt)。
5.1 本地提示词(Local Prompt)
本地提示词是直接在代码中定义的模板。它们支持使用 {variable_name} 语法进行变量替换,且可由文本字符串或消息序列创建。
本地提示词有两种创建方式:Prompt.from_text()和Prompt.from_messages()
product_suggestion_prompt_str = """
Based on the rating distribution and user dissatisfaction reasons, generate three actionable suggestions for product improvement.
Input format:
{{
"id": "1",
"score_histogram": ["10%", "20%", "10%", "15%", "45%"],
"unsatisfied_reasons": ["reason1", "reason2", "reason3"]
}}
Ensure that your response can be parsed by Python json, use the following format as an example:
{{
"suggestion_list": [
"suggestion1",
"suggestion2",
"suggestion3"
]
}}
input:
{input}
"""
product_suggestion_prompt = Prompt.from_text(product_suggestion_prompt_str)
review_analysis_prompt = Prompt.from_messages(
messages=[
ChatMessage(
role=MessageRole.SYSTEM,
content="""
Analyze the user review and product information to determine a
satisfaction score (1-5) and potential reasons for dissatisfaction.
Example input format:
{{
"id": "12345",
"review": "The headphones broke after one week of use."
}}
Ensure your response can be parsed by Python JSON:
{{
"id": "12345",
"score": 1,
"reasons": ["poor quality"]
}}
""",
),
ChatMessage(
role=MessageRole.USER,
content="""
"input":
{input}
""",
),
],
)
本地提示词的使用:
提示词(Prompts)使用 {variable_name} 语法定义模板变量。变量值从 ChatMessage.extra_args 中获取填充。当对话模型(chat model)被调用时,该提示词会自动生效。
class ReviewAnalysisAgent(Agent):
@prompt
@staticmethod
def review_analysis_prompt() -> Prompt:
"""Prompt for review analysis."""
return Prompt.from_messages(
messages=[
ChatMessage(
role=MessageRole.SYSTEM,
content="""
Analyze the user review and product information to determine a
satisfaction score (1-5) and potential reasons for dissatisfaction.
Example input format:
{{
"id": "12345",
"review": "The headphones broke after one week of use."
}}
Ensure your response can be parsed by Python JSON:
{{
"id": "12345",
"score": 1,
"reasons": ["poor quality"]
}}
""",
),
ChatMessage(
role=MessageRole.USER,
content="""
"input":
{input}
""",
),
],
)
@chat_model_setup
@staticmethod
def review_analysis_model() -> ResourceDescriptor:
"""ChatModel which focus on review analysis."""
return ResourceDescriptor(
clazz=OllamaChatModelSetup,
connection="ollama_server",
model="qwen3:8b",
prompt="review_analysis_prompt",
extract_reasoning=True,
)
@action(InputEvent)
@staticmethod
def process_input(event: InputEvent, ctx: RunnerContext) -> None:
"""Process input event and send chat request for review analysis."""
input: ProductReview = event.input
ctx.short_term_memory.set("id", input.id)
content = f"""
"id": {input.id},
"review": {input.review}
"""
msg = ChatMessage(role=MessageRole.USER, extra_args={"input": content})
ctx.send_event(ChatRequestEvent(model="review_analysis_model", messages=[msg]))
5.2 MCP提示词(MCP Prompt)
MCP 提示词(MCP Prompt)由外部 MCP 服务器(MCP Server)管理,当您在智能体(Agent)中定义 MCP 服务器连接后,这些提示词会被自动发现。这类提示词支持动态获取提示词、集中式提示词管理,以及与外部提示词仓库的集成。
使用 FastMCP 库创建一个可对外提供提示词(Prompts)访问的 MCP 服务器:
# mcp_server.py
mcp = FastMCP("ReviewServer")
@mcp.prompt()
def review_analysis_prompt(product_id: str, review: str) -> str:
"""Prompt for analyzing product reviews."""
return f"""
Analyze the following product review and provide a satisfaction score (1-5).
Product ID: {product_id}
Review: {review}
Output format: {{"score": 1-5, "reasons": ["reason1", "reason2"]}}
"""
mcp.run("streamable-http")
MCP提示词的使用:
- 使用@mcp_server装饰器定义 MCP 服务器连接
- 通过 MCP 提示词的函数名引用该提示词(例如:“review_analysis_prompt”)
- 使用ChatMessage.extra_args提供提示词参数
- MCP 服务器中的所有提示词(Prompts)和工具(Tools)会被自动注册
class ReviewAnalysisAgent(Agent):
@mcp_server
@staticmethod
def review_mcp_server() -> MCPServer:
"""Connect to MCP server."""
return MCPServer(endpoint="http://127.0.0.1:8000/mcp")
@chat_model_connection
@staticmethod
def ollama_server() -> ResourceDescriptor:
"""Ollama connection."""
return ResourceDescriptor(clazz=OllamaChatModelConnection)
@chat_model_setup
@staticmethod
def review_model() -> ResourceDescriptor:
return ResourceDescriptor(
clazz=OllamaChatModelSetup,
connection="ollama_server",
model="qwen3:8b",
prompt="review_analysis_prompt", # Reference MCP prompt by name
)
@action(InputEvent)
@staticmethod
def process_input(event: InputEvent, ctx: RunnerContext) -> None:
input_data = event.input
# Provide prompt variables via extra_args
msg = ChatMessage(
role=MessageRole.USER,
extra_args={
"product_id": input_data.product_id,
"review": input_data.review
}
)
ctx.send_event(ChatRequestEvent(model="review_model", messages=[msg]))
6、Tool Use(工具使用)
Flink Agents提供了灵活且可扩展的工具使用机制。开发者既可以将工具定义为本地 Python 函数,也可以与远程 MCP 服务器集成,以使用 MCP 服务器提供的工具。
- 本地函数作为工具
开发者可将工具定义为本地Python函数,且将本地函数定义并注册为工具。存在两种方式:-
将工具定义为智能体类中的静态方法
开发者在定义智能体时,可将工具定义为智能体类(agent class)中的静态方法(static method),并在 Python 中使用@tool装饰器(decorator)将该函数标记为工具。在智能体中创建对话模型(chat model)时,可在资源描述符(ResourceDescriptor)的工具列表(tools list)中通过工具名称引用该工具。class ReviewAnalysisAgent(Agent): @tool @staticmethod def notify_shipping_manager(id: str, review: str) -> None: """Notify the shipping manager when product received a negative review due to shipping damage. Parameters ---------- id : str The id of the product that received a negative review due to shipping damage review: str The negative review content """ notify_shipping_manager(id=id, review=review) @chat_model_setup @staticmethod def review_analysis_model() -> ResourceDescriptor: """ChatModel which focus on review analysis.""" return ResourceDescriptor( clazz=OllamaChatModelSetup, ..., tools=["notify_shipping_manager"], # reference the tool by its name ) ... -
向执行环境注册工具
开发者可将工具注册到执行环境(execution environment)中,之后通过工具名称引用该工具。这种方式能让多个智能体(agents)复用该工具。def notify_shipping_manager(id: str, review: str) -> None: """Notify the shipping manager when product received a negative review due to shipping damage. Parameters ---------- id : str The id of the product that received a negative review due to shipping damage review: str The negative review content """ ... ... # Add notify shipping manager tool to the execution environment. agents_env.add_resource( "notify_shipping_manager", Tool.from_callable(notify_shipping_manager) ) ... # Create react agent with notify shipping manager tool. review_analysis_react_agent = ReActAgent( chat_model=ResourceDescriptor( clazz=OllamaChatModelSetup, tools=["notify_shipping_manager"], # reference the tool by its name ), ... )
-
- MCP 工具
MCP 工具(MCP Tools)由外部 MCP 服务器(Model Context Protocol Server,模型上下文协议服务器)管理,当您在智能体(Agent)中定义 MCP 服务器连接后,这些工具会被自动发现。
定义带工具的 MCP 服务器
使用 FastMCP 库创建一个可对外提供工具访问的 MCP 服务器:
# mcp_server.py
mcp = FastMCP("ReviewServer")
@mcp.tool()
async def notify_shipping_manager(id: str, review: str) -> None:
"""Notify the shipping manager when product received a negative review due to
shipping damage.
Parameters
----------
id : str
The id of the product that received a negative review due to shipping damage
review: str
The negative review content
"""
...
mcp.run("streamable-http")
使用MCP工具:
class ReviewAnalysisAgent(Agent):
...
@mcp_server
@staticmethod
def review_mcp_server() -> MCPServer:
"""Connect to MCP server."""
return MCPServer(endpoint="http://127.0.0.1:8000/mcp")
@chat_model_setup
@staticmethod
def review_model() -> ResourceDescriptor:
return ResourceDescriptor(
clazz=OllamaChatModelSetup,
connection="ollama_server",
model="qwen3:8b",
tools=["notify_shipping_manager"], # Reference MCP tool by name
)
7、Memory(记忆)
记忆(Memory)是在多个行动(Actions)和智能体运行(agent runs)过程中可被保留的数据。
- 短期记忆(Short-Term Memory)
短期记忆在一次智能体运行(agent run)内的所有动作间共享,同时也在 “具有相同输入键(input key)” 的多次智能体运行间共享。 此处的 “智能体运行(agent run)” 指智能体的一次完整执行过程。上游(upstream)传来的每一条数据记录,都会触发一次新的智能体运行。 短期记忆对应 Flink 的 “键控状态(Keyed State)”:键控状态对 “同一键控分区(keyed partition)内多条数据记录的处理过程” 可见,而对 “其他键控分区中数据的处理过程” 不可见(即具有分区隔离性)。
基本使用方法:
@action(InputEvent)
@staticmethod
def first_action(event: InputEvent, ctx: RunnerContext) -> None:
...
ctx.short_term_memory.set("id", input.id)
...
@action(ChatResponseEvent)
@staticmethod
def second_action(event: ChatResponseEvent, ctx: RunnerContext) -> None:
...
id = ctx.short_term_memory.get("id"),
...
存储为嵌套对象:
@action(InputEvent)
@staticmethod
def first_action(event: InputEvent, ctx: RunnerContext) -> None:
...
stm = ctx.short_term_memory
# create nested memory object, and then set the leaf value
nested_obj = stm.new_object("a")
nested_obj.set("b", input.id)
# directly set leaf value, will auto crate the nested object
stm.set("x.y", input.user)
...
@action(ChatResponseEvent)
@staticmethod
def second_action(event: InputEvent, ctx: RunnerContext) -> None:
...
stm = ctx.short_term_memory
# directly get leaf value, will auto parse the nested object
id = stm.get("a.b")
# get the nested object, and then get the leaf value
nested_obj = stm.get("x")
user = nested_obj.get("y")
...
记忆引用:
@staticmethod
def first_action(event: Event, ctx: RunnerContext): # noqa D102
...
stm = ctx.get_short_term_memory()
data_ref = stm.set(data_path, data_to_store)
ctx.send_event(MyEvent(value=data_ref))
...
@action(MyEvent)
@staticmethod
def second_action(event: Event, ctx: RunnerContext): # noqa D102
...
stm = ctx.get_short_term_memory()
content_ref: MemoryRef = event.value
processed_data: ProcessedData = stm.get(content_ref)
...
总结
本文介绍了Flink Agents框架的基础组件,了解这些基础组件是开发者基于Flink Agents构建智能体系统的基石。后面我们将通过应用实例探讨基于Flink Agents的智能体开发以及怎样和Flink引擎集成在一起成为一个事件驱动型智能体系统。