Skip to content

Commit 67a4e40

Browse files
locross93copybara-github
authored andcommitted
An agent that generates engaging conversation
PiperOrigin-RevId: 800404445 Change-Id: Iadd1d0784967ddbd844e1232c235eb393b5f8f38
1 parent eddc2fb commit 67a4e40

2 files changed

Lines changed: 206 additions & 0 deletions

File tree

concordia/prefabs/entity/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
from concordia.prefabs.entity import basic
1818
from concordia.prefabs.entity import basic_scripted
1919
from concordia.prefabs.entity import basic_with_plan
20+
from concordia.prefabs.entity import conversational
2021
from concordia.prefabs.entity import fake_assistant_with_configurable_system_prompt
2122
from concordia.prefabs.entity import minimal
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Copyright 2025 DeepMind Technologies Limited.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""A conversational agent designed to produce engaging dynamics."""
16+
17+
import dataclasses
18+
from typing import Mapping
19+
20+
from concordia.agents import entity_agent_with_logging
21+
from concordia.associative_memory import basic_associative_memory
22+
from concordia.components import agent as agent_components
23+
from concordia.components.agent import question_of_recent_memories
24+
from concordia.language_model import language_model
25+
from concordia.typing import prefab as prefab_lib
26+
27+
28+
CONVERSATION_DYNAMICS_QUESTION = (
29+
'As {agent_name}, your goal is to maintain an engaging conversation.'
30+
' This means balancing stability (staying on topic) with flexibility'
31+
' (introducing new, related ideas). Review the recent conversation.'
32+
' Has the immediate micro-topic become interesting or repetitive?'
33+
' Based on this, choose a strategy for what to say next:\nA.'
34+
' **Converge:** Stay on the micro-topic to deepen the conversation for'
35+
' several turns. Choose this if the topic has more to explore.\nB.'
36+
' **Diverge:** Broaden the topic by connecting it to a more abstract'
37+
' theme, a related personal anecdote, or a question about them. Choose'
38+
' this if the current micro-topic is becoming repetitive after several'
39+
" turns.\n Don't diverge too much, and don't introduce too many new"
40+
' micro-topics. You should aim to stay on the current micro-topic for'
41+
' a few turns, and then diverge.'
42+
)
43+
44+
45+
@dataclasses.dataclass
46+
class Entity(prefab_lib.Prefab):
47+
"""A prefab for a conversational agent aiming for engaging dynamics."""
48+
49+
description: str = (
50+
'An entity that participates in conversations, aiming to create a '
51+
'dynamically balanced and engaging dialogue.'
52+
)
53+
params: Mapping[str, str] = dataclasses.field(
54+
default_factory=lambda: {
55+
'name': 'Debra',
56+
}
57+
)
58+
59+
def build(
60+
self,
61+
model: language_model.LanguageModel,
62+
memory_bank: basic_associative_memory.AssociativeMemoryBank,
63+
) -> entity_agent_with_logging.EntityAgentWithLogging:
64+
"""Build the conversational agent.
65+
66+
Args:
67+
model: The language model to use.
68+
memory_bank: The memory bank to use.
69+
70+
Returns:
71+
An entity agent.
72+
"""
73+
entity_name = self.params.get('name', 'Debra')
74+
conversation_style = self.params.get('conversation_style', '')
75+
76+
memory_key = agent_components.memory.DEFAULT_MEMORY_COMPONENT_KEY
77+
memory = agent_components.memory.AssociativeMemory(memory_bank=memory_bank)
78+
79+
instructions_key = 'Instructions'
80+
instructions = agent_components.instructions.Instructions(
81+
agent_name=entity_name,
82+
pre_act_label='\nInstructions',
83+
)
84+
85+
observation_to_memory_key = 'Observation'
86+
observation_to_memory = agent_components.observation.ObservationToMemory()
87+
88+
observation_key = (
89+
agent_components.observation.DEFAULT_OBSERVATION_COMPONENT_KEY
90+
)
91+
observation = agent_components.observation.LastNObservations(
92+
history_length=100,
93+
pre_act_label=(
94+
'\nEvents so far (ordered from least recent to most recent)'
95+
),
96+
)
97+
98+
situation_perception_key = 'SituationPerception'
99+
situation_perception = (
100+
agent_components.question_of_recent_memories.SituationPerception(
101+
model=model,
102+
pre_act_label=(
103+
f'\nQuestion: What situation is {entity_name} in right now?'
104+
'\nAnswer'
105+
),
106+
)
107+
)
108+
self_perception_key = 'SelfPerception'
109+
self_perception = (
110+
agent_components.question_of_recent_memories.SelfPerception(
111+
model=model,
112+
pre_act_label=(
113+
f'\nQuestion: What kind of person is {entity_name}?\nAnswer'
114+
),
115+
)
116+
)
117+
last_sentence_key = 'LastSentence'
118+
last_sentence = question_of_recent_memories.QuestionOfRecentMemories(
119+
model=model,
120+
pre_act_label=(
121+
'\nQuestion: Is there something in the last'
122+
f' sentence in the conversation that {entity_name} could respond'
123+
' to to move the conversation forward?\nAnswer'
124+
),
125+
num_memories_to_retrieve=2,
126+
question=(
127+
'Is there something in the last sentence in the conversation that'
128+
f' {entity_name} could respond to to move the conversation forward?'
129+
),
130+
answer_prefix='',
131+
add_to_memory=False,
132+
)
133+
134+
relevant_memories_key = 'RelevantMemories'
135+
relevant_memories_components = [situation_perception_key]
136+
relevant_memories = (
137+
agent_components.all_similar_memories.AllSimilarMemories(
138+
model=model,
139+
components=relevant_memories_components,
140+
num_memories_to_retrieve=5,
141+
pre_act_label='\nRecalled relevantmemories and observations',
142+
)
143+
)
144+
145+
if conversation_style:
146+
convo_style_key = 'ConversationStyle'
147+
conversation_style = agent_components.constant.Constant(
148+
state=conversation_style,
149+
pre_act_label='\nConversation Style',
150+
)
151+
else:
152+
convo_style_key = None
153+
conversation_style = None
154+
155+
convo_components = [
156+
situation_perception_key,
157+
self_perception_key,
158+
last_sentence_key,
159+
]
160+
if convo_style_key:
161+
convo_components.insert(2, convo_style_key)
162+
conversation_dynamics_key = 'ConversationDynamics'
163+
conversation_dynamics = (
164+
question_of_recent_memories.QuestionOfRecentMemories(
165+
model=model,
166+
pre_act_label=f'\n{CONVERSATION_DYNAMICS_QUESTION}',
167+
question=CONVERSATION_DYNAMICS_QUESTION,
168+
components=convo_components,
169+
num_memories_to_retrieve=100,
170+
answer_prefix='',
171+
add_to_memory=False,
172+
memory_tag='[conversation dynamics]',
173+
)
174+
)
175+
176+
components_of_agent = {
177+
instructions_key: instructions,
178+
observation_to_memory_key: observation_to_memory,
179+
relevant_memories_key: relevant_memories,
180+
observation_key: observation,
181+
self_perception_key: self_perception,
182+
situation_perception_key: situation_perception,
183+
last_sentence_key: last_sentence,
184+
conversation_dynamics_key: conversation_dynamics,
185+
memory_key: memory,
186+
}
187+
188+
component_order = list(components_of_agent.keys())
189+
190+
if convo_style_key:
191+
components_of_agent[convo_style_key] = conversation_style
192+
component_order.insert(5, convo_style_key)
193+
194+
act_component = agent_components.concat_act_component.ConcatActComponent(
195+
model=model,
196+
component_order=component_order,
197+
)
198+
199+
agent = entity_agent_with_logging.EntityAgentWithLogging(
200+
agent_name=entity_name,
201+
act_component=act_component,
202+
context_components=components_of_agent,
203+
)
204+
205+
return agent

0 commit comments

Comments
 (0)