Avertissement
Les citations sont expérimentales. Le nom de l’option, la charge utile d’événement et la couverture du fournisseur peuvent changer dans une version ultérieure.
Fonctionnement des citations
Les citations sont produites par le fournisseur de modèles, et non par le Kit de développement logiciel (SDK). Le flux comporte trois parties :
- Votre application fournit des documents citables, tels qu’une pièce jointe de document ou un résultat d’outil qui contient du contenu source.
- L’environnement d’exécution marque ce contenu comme pouvant être cité sur le réseau lorsque
enableCitationsest activé. Pour les modèles Anthropic, les fichiers joints sont envoyés sous forme de blocsdocumentavec les citations activées. - Le modèle renvoie des métadonnées de citation, et l’environnement d’exécution les normalise en un objet
citationsindépendant du fournisseur lors de l’événement finalassistant.message.
La prise en charge du fournisseur est limitée. Champ provider sur chaque enregistrement source à partir duquel la citation provient :
| Valeur du fournisseur | Sens |
|---|---|
anthropic | Citation produite par une réponse du modèle Anthropic (Claude) |
openai | Citation produite par une réponse de modèle OpenAI |
client | Citation synthétisée par le runtime à partir de la sortie de l’outil |
Remarque
L’activation enableCitations ne garantit pas qu’une réponse contient des citations. Les modèles les émettent uniquement lorsque la réponse est ancrée dans le matériau source citable. Traitez toujours le citations champ comme facultatif.
Activer les citations sur une session
Définissez l’option sur la création de session et définissez-la à nouveau sur reprise si vous souhaitez des citations après un redémarrage.
const session = await client.createSession({
onPermissionRequest: approveAll,
enableCitations: true,
});
const resumed = await client.resumeSession(session.sessionId, {
onPermissionRequest: approveAll,
enableCitations: true,
});
session = await client.create_session(
on_permission_request=PermissionHandler.approve_all,
enable_citations=True,
)
resumed = await client.resume_session(
session.session_id,
on_permission_request=PermissionHandler.approve_all,
enable_citations=True,
)
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
EnableCitations: copilot.Bool(true),
})
resumed, err := client.ResumeSession(ctx, session.SessionID, &copilot.ResumeSessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
EnableCitations: copilot.Bool(true),
})
var session = await client.CreateSessionAsync(new SessionConfig
{
OnPermissionRequest = PermissionHandler.ApproveAll,
EnableCitations = true,
});
var resumed = await client.ResumeSessionAsync(session.SessionId, new ResumeSessionConfig
{
OnPermissionRequest = PermissionHandler.ApproveAll,
EnableCitations = true,
});
CopilotSession session = client
.createSession(new SessionConfig()
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
.setEnableCitations(true))
.get();
CopilotSession resumed = client
.resumeSession(session.getSessionId(), new ResumeSessionConfig()
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
.setEnableCitations(true))
.get();
let session = client
.create_session(
SessionConfig::new()
.approve_all_permissions()
.with_enable_citations(true),
)
.await?;
let resumed = client
.resume_session(
ResumeSessionConfig::new(session.id().clone())
.approve_all_permissions()
.with_enable_citations(true),
)
.await?;
Lire des citations à partir de messages d’assistant
Les citations arrivent lors de l’événement final assistant.message, et non lors des événements assistant.message_delta. Attendez le message final avant de restituer les marqueurs sources.
session.on((event) => {
if (event.type !== "assistant.message" || !event.data.citations) {
return;
}
const { sources, spans } = event.data.citations;
const sourceById = new Map(sources.map((source) => [source.id, source]));
for (const span of spans) {
const quoted = event.data.content.slice(span.startIndex, span.endIndex);
for (const reference of span.references) {
const source = sourceById.get(reference.sourceId);
const label = source?.title ?? source?.url ?? source?.path ?? source?.id;
console.log(`"${quoted}" — ${label}`);
}
}
});
from copilot.session_events import SessionEventType
def utf16_slice(text: str, start: int, end: int) -> str:
"""Slice by UTF-16 code units, which is how span offsets are measured."""
units = text.encode("utf-16-le")
return units[start * 2 : end * 2].decode("utf-16-le")
def handle(event):
if event.type != SessionEventType.ASSISTANT_MESSAGE or not event.data.citations:
return
sources = {source.id: source for source in event.data.citations.sources}
for span in event.data.citations.spans:
quoted = utf16_slice(event.data.content, span.start_index, span.end_index)
for reference in span.references:
source = sources[reference.source_id]
label = source.title or source.url or source.path or source.id
print(f'"{quoted}" — {label}')
session.on(handle)
// import "unicode/utf16"
session.On(func(event copilot.SessionEvent) {
d, ok := event.Data.(*copilot.AssistantMessageData)
if !ok || d.Citations == nil {
return
}
sources := map[string]copilot.CitationSource{}
for _, source := range d.Citations.Sources {
sources[source.ID] = source
}
// Span offsets are UTF-16 code units, so index the UTF-16 view of the content.
units := utf16.Encode([]rune(d.Content))
for _, span := range d.Citations.Spans {
quoted := string(utf16.Decode(units[span.StartIndex:span.EndIndex]))
for _, reference := range span.References {
source := sources[reference.SourceID]
label := source.ID
switch {
case source.Title != nil:
label = *source.Title
case source.URL != nil:
label = *source.URL
case source.Path != nil:
label = *source.Path
}
fmt.Printf("%q — %s\n", quoted, label)
}
}
})
session.On<SessionEvent>(evt =>
{
if (evt is not AssistantMessageEvent message || message.Data.Citations is null)
{
return;
}
var sources = message.Data.Citations.Sources.ToDictionary(source => source.Id);
foreach (var span in message.Data.Citations.Spans)
{
var quoted = message.Data.Content[(int)span.StartIndex..(int)span.EndIndex];
foreach (var reference in span.References)
{
var source = sources[reference.SourceId];
var label = source.Title ?? source.Url ?? source.Path ?? source.Id;
Console.WriteLine($"\"{quoted}\" — {label}");
}
}
});
session.on(AssistantMessageEvent.class, event -> {
Citations citations = event.getData().citations();
if (citations == null) {
return;
}
Map<String, CitationSource> sources = citations.sources().stream()
.collect(Collectors.toMap(CitationSource::id, source -> source));
for (CitationSpan span : citations.spans()) {
String quoted = event.getData().content()
.substring(span.startIndex().intValue(), span.endIndex().intValue());
for (CitationReference reference : span.references()) {
CitationSource source = sources.get(reference.sourceId());
String label = source.title() != null ? source.title()
: source.url() != null ? source.url()
: source.path() != null ? source.path()
: source.id();
System.out.printf("\"%s\" — %s%n", quoted, label);
}
}
});
use github_copilot_sdk::session_events::AssistantMessageData;
use std::collections::HashMap;
let mut events = session.subscribe();
while let Ok(event) = events.recv().await {
if event.event_type != "assistant.message" {
continue;
}
let Some(data) = event.typed_data::<AssistantMessageData>() else {
continue;
};
let Some(citations) = data.citations.as_ref() else {
continue;
};
let sources: HashMap<&str, _> = citations
.sources
.iter()
.map(|source| (source.id.as_str(), source))
.collect();
// Span offsets are UTF-16 code units, so index the UTF-16 view of the content.
let units: Vec<u16> = data.content.encode_utf16().collect();
for span in &citations.spans {
let quoted = String::from_utf16_lossy(
&units[span.start_index as usize..span.end_index as usize],
);
for reference in &span.references {
let Some(source) = sources.get(reference.source_id.as_str()) else {
continue;
};
let label = source
.title
.as_deref()
.or(source.url.as_deref())
.or(source.path.as_deref())
.unwrap_or(source.id.as_str());
println!("\"{quoted}\" — {label}");
}
}
}
Informations de référence sur la charge utile de citation
L’objet citations sépare les sources dédupliquées des étendues qui les référencent. Par conséquent, une source citée cinq fois apparaît une fois dans sources.
| Type | Champ | Description |
|---|---|---|
Citations | sources | Ensemble dédupliqué des sources référencées dans les segments de citation |
Citations | spans | Segments de texte généré annotés avec leurs sources justificatives |
CitationSource | id | Identificateur stable et délimité par tour référencé par Citation |
CitationSource | provider | Système qui a produit la citation : anthropic, openaiou client |
CitationSource | title? | Titre lisible par l’homme de la source |
CitationSource | url? | URL de la source, lorsqu’il s’agit d’une ressource web |
CitationSource | path? | Chemin d’accès du fichier par rapport au répertoire racine de l’espace de travail de l’agent, si la source est un fichier |
CitationSpan | startIndex | Décalage de début dans le contenu final du message (unités de code UTF-16, à base de zéro, inclusif) |
CitationSpan | endIndex | Décalage de fin dans le contenu final du message (unités de code UTF-16, de base zéro, exclusives) |
CitationSpan | references | Sources qui prennent en charge cette étendue |
CitationReference | sourceId | Identificateur de CitationSource vers lequel pointe cette référence |
CitationReference | citedText? | Texte exact de la source qui prend en charge l’étendue, lorsque le modèle le fournit |
CitationReference | location? | Emplacement dans le texte source qui justifie le segment |
CitationReference | providerMetadata? | Données de corrélation natives du fournisseur, transmises de manière opaque |
Conseil
Les décalages d’étendue sont mesurés en unités de code UTF-16 par rapport à la chaîne finale content . TypeScript, Java et chaînes .NET sont déjà UTF-16. Vous pouvez donc les découper directement. Les chaînes Python sont indexées selon les points de code Unicode, et les chaînes Go et Rust sont encodées en UTF-8 ; convertissez donc le contenu en unités de code UTF-16 avant de les découper, comme le montrent les exemples ci-dessus.
Emplacements de citation
CitationReference.location est une union discriminée indexée par type :
| Type d’emplacement | Fields | Utilisation |
|---|---|---|
char | ||
startIndex, endIndex | Plage de caractères dans le texte source | |
page | ||
startPage, endPage | Plage de pages dans un document paginé | |
block | ||
startBlock, endBlock | Plage de blocs de contenu dans un document structuré |
Fournir des sources citables
Les citations ont besoin d’un matériau source que le modèle peut attribuer. Il existe deux façons de le fournir.
Joindre des documents à un message
Lorsque des citations sont activées et que la session utilise un fournisseur de Anthropic, les pièces jointes de fichiers sont envoyées sous forme document de blocs avec des citations activées, afin que le modèle puisse citer des passages à partir d’eux.
await session.sendAndWait({
prompt: "Summarize the attached PDF and cite the passages you used.",
attachments: [
{
type: "blob",
data: pdfBase64,
displayName: "quarterly-report.pdf",
mimeType: "application/pdf",
},
],
});
Consultez Entrée d’image pour l’API des pièces jointes ainsi que les formats de pièces jointes file et blob.
Retourner des sources citables à partir d’un outil
Les résultats de l’outil incluent un tableau expérimental citableSources. Chaque entrée fournit content que le modèle peut citer, ainsi qu’un id et, éventuellement, title, url et path. Ces sources sont conservées avec le résultat de l’outil, de sorte qu’elles restent disponibles après la reprise de la session, et les citations générées à partir de celles-ci sont étiquetées avec le fournisseur client.
Limitations
- Les citations sont expérimentales dans chaque Kit de développement logiciel (SDK) et ne sont pas couvertes par des garanties de compatibilité.
- La couverture dépend du fournisseur de modèles. Une session configurée pour un fournisseur sans prise en charge des citations n’émet aucun payload
citations. - Les citations ne sont présentes que dans le dernier événement
assistant.message, de sorte que les clients en streaming ne peuvent pas les afficher en cours de réponse. - Les citations de code public et de duplication IP ne font pas partie de cette surface.
Lectures complémentaires
- Événements de session de streaming : s’abonner aux événements de session et aux types d’événements étroits
- Entrée d’image : attacher des fichiers et des objets blob en mémoire à un message
- Reprise de session et persistance : reprendre les sessions et réappliquer des options de session
- Compatibilité du Kit de développement logiciel (SDK) et de l’interface : Matrice de fonctionnalités du KIT DE développement logiciel (SDK) et de l’interface CLI